package cn.com.tenlion.systembase.listener;

import cn.com.tenlion.systembase.pojo.dtos.excel.ImportFailDto;
import cn.com.tenlion.systembase.pojo.dtos.excel.ImportSuccessDto;
import cn.com.tenlion.systembase.pojo.model.school.SchoolModel;
import cn.com.tenlion.systembase.service.handleimportexcel.IHandleImportExcelService;
import cn.com.tenlion.systembase.util.ImportExcelHelper;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 导入excel的监听处理类
 * @author renpc
 */
public class ImportExcelListener<T> extends AnalysisEventListener<T>{

    private static final int BATCH_COUNT = 1000;

    /**
     * 导入成功的数据
     */
    private List<ImportSuccessDto> importSuccessDtoList = new ArrayList<>();
    /**
     * 导入失败的数据
     */
    private List<ImportFailDto> importFailDtoList = new ArrayList<>();

    /**
     * 保存数据库专用list
     */
    private List<T> list = new ArrayList<>();

    /**
     * 去重专用list
     */
    private List<T> listForDistinct = new ArrayList<>();

    /**
     * 处理导入数据的逻辑
     */
    private IHandleImportExcelService handleImportExcelService;

    private Class<T> tClass;

    public List<ImportSuccessDto> getImportSuccessDtoList() {
        return importSuccessDtoList;
    }

    public void setImportSuccessDtoList(List<ImportSuccessDto> importSuccessDtoList) {
        this.importSuccessDtoList = importSuccessDtoList;
    }

    public List<ImportFailDto> getImportFailDtoList() {
        return importFailDtoList;
    }

    public void setImportFailDtoList(List<ImportFailDto> importFailDtoList) {
        this.importFailDtoList = importFailDtoList;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public IHandleImportExcelService getHandleImportExcelService() {
        return handleImportExcelService;
    }

    public void setHandleImportExcelService(IHandleImportExcelService handleImportExcelService) {
        this.handleImportExcelService = handleImportExcelService;
    }

    public Class<T> gettClass() {
        return tClass;
    }

    public void settClass(Class<T> tClass) {
        this.tClass = tClass;
    }

    public ImportExcelListener(IHandleImportExcelService handleImportExcelService) {
        this.handleImportExcelService = handleImportExcelService;
    }

    public ImportExcelListener(IHandleImportExcelService handleImportExcelService, Class<T> tClass) {
        this.handleImportExcelService = handleImportExcelService;
        this.tClass = tClass;
    }

    /**
     * 导入数据的处理逻辑
     * @param t
     * @param analysisContext
     */
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        // 错误提示
        String msg = "";
        try {
            msg = ImportExcelHelper.checkDataValid(t);
        }catch (Exception e){
            msg = "存在空数据";
            e.printStackTrace();
        }

        // 如果校验失败
        if(msg.length() != 0){
            ImportFailDto importFailDto = new ImportFailDto(t, msg);
            importFailDtoList.add(importFailDto);
        }else{
            ImportExcelHelper.checkDataFromDatabase(t);
            list.add(t);
            listForDistinct.add(t);
        }

        if(list.size() > BATCH_COUNT){
            try {
                insertData();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 所有数据处理完之后的处理方法
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // PS:之所以最后这里还进行处理是防止最后一次的数据量没有达到批量值
        if(list.size() > 0) {
            try {
                insertData();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 校验导入的表格的头是否匹配
     * @param headMap
     * @param analysisContext
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext analysisContext){
        super.invokeHeadMap(headMap, analysisContext);
        if(tClass != null){
            try {
                // 获取Excel导入实体的单元格内容
                Map<Integer, String> indexNameMap = getIndexName(tClass);
                Set<Integer> keySet = indexNameMap.keySet();
                for (Integer key: keySet) {
                    // 头表是否存在空值
                    if(headMap.get(key).length() == 0){
                        throw new ExcelAnalysisException("Excel格式非法");
                    }
                    // 对比导入Excel实体模板和当前上传Excel是否匹配
                    /*if(!headMap.get(key).equals(indexNameMap.get(key))){
                        throw new ExcelAnalysisException("Excel格式非法");
                    }*/
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private Map<Integer, String> getIndexName(Class<T> tClass) throws NoSuchFieldException {
        Map<Integer, String> result = new HashMap<>();
        Field[] declaredFields = tClass.getDeclaredFields();
        for (Field currentField: declaredFields) {
            currentField.setAccessible(true);
            ExcelProperty annotation = currentField.getAnnotation(ExcelProperty.class);
            if(annotation != null){
                int index =annotation.index();
                String[] value = annotation.value();
                StringBuilder sb = new StringBuilder();
                for (String cur : value) {
                    sb.append(cur);
                }
                result.put(index, sb.toString());
            }
        }
        return result;
    }

    /**
     * 将数据插入数据库操作
     */
    private void insertData() throws Exception {
        String value = "";
        // 房屋信息
        if(list.get(0) instanceof SchoolModel) {
            List<SchoolModel> schoolModelList = (List<SchoolModel>) list;
            handleImportExcelService.saveSchool(schoolModelList, importFailDtoList);
        }
        listForDistinct.clear();
        list.clear();
    }


}