package com.qmth.boot.tools.excel.model;

import com.qmth.boot.tools.excel.annotation.ExcelColumn;
import com.qmth.boot.tools.excel.convertor.ValueConvertor;
import com.qmth.boot.tools.excel.convertor.ValueConvertors;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class ObjectParam extends HashMap<String, FieldParam> {

    private static final long serialVersionUID = 3789838085423920607L;

    private static Map<Class<?>, ObjectParam> paramMap = new ConcurrentHashMap<>();

    public static ObjectParam get(Class<?> clazz) {
        ObjectParam param = paramMap.get(clazz);
        if (param == null) {
            param = paramMap.computeIfAbsent(clazz, ObjectParam::new);
        }
        return param;
    }

    private String[] columnNames;

    private List<FieldParam> fieldList;

    private ObjectParam(Class<?> objectType) {
        super();

        Field[] fields = objectType.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
            if (annotation != null) {
                if (!ValueConvertors.containsType(field.getType())) {
                    if (!annotation.convertor().equals(ValueConvertor.class)) {
                        try {
                            ValueConvertors.register(field.getType(), annotation.convertor().newInstance());
                        } catch (Exception e) {
                            throw new RuntimeException(
                                    "Unsupported convertor in @ExcelColumn: " + annotation.convertor());
                        }
                    } else {
                        throw new RuntimeException("Unsupported field type with @ExcelColumn: " + field.getType());
                    }
                }
                put(annotation.name(), new FieldParam(field, annotation));
            }
        }

        fieldList = new ArrayList<>(values());
        fieldList.sort(Comparator.comparingInt(p -> p.getAnnotation().index()));
        columnNames = fieldList.stream().map(p -> p.getAnnotation().name()).toArray(String[]::new);
    }

    public String[] getColumnNames() {
        return columnNames;
    }

    /**
     * 验证解析的列名，需要所有非空字段对应的列名存在
     * 返回缺少的列名，不缺时返回集合为空
     *
     * @param columnNames
     * @return
     */
    public Set<String> validate(String[] columnNames) {
        Set<String> columnSet = fieldList.stream().filter(p -> !p.getAnnotation().nullable())
                .map(p -> p.getAnnotation().name()).collect(Collectors.toCollection(LinkedHashSet::new));
        if (ArrayUtils.isEmpty(columnNames)) {
            return columnSet;
        }
        for (String name : columnNames) {
            columnSet.remove(name);
        }
        return columnSet;
    }
}
