package com.cf.imes.module.executor.service.manage.parts;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.nacos.common.utils.StringUtils;
import com.cf.imes.framework.excel.core.convert.BaseBoolValEnum;
import com.cf.imes.framework.excel.core.enums.WhetherEnum;
import com.cf.imes.module.executor.controller.admin.manage.parts.vo.PartsImportExcelVO;
import com.cf.imes.module.executor.enums.manage.parts.CategoryEnum;
import com.cf.imes.module.executor.enums.manage.parts.ObjectEnum;
import com.cf.imes.module.executor.util.file.ExcelListener;
import lombok.extern.slf4j.Slf4j;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 配件 导入监听器
 */
@Slf4j
public final class PartsExcelListener extends ExcelListener<PartsImportExcelVO> {

    private static final String ZERO = "0";

    /**
     * 自定义用于暂时存储data
     * 可以通过实例获取该值
     */
    private List<PartsImportExcelVO> datas = new ArrayList<>();

    private boolean flag = true;

    private Map<Integer, String> valueMap = new HashMap<>();

    // 非空判断，错误写入；不为空则判断字符串长度是否超过
    private void isEmptyAndAdd(Supplier<String> getter, Consumer<String> setter,String msg, int maxLength) {
        String value = getter.get();
        if (StringUtils.isEmpty(value)) {
            setter.accept(msg + "不可为空");
            this.flag = false;
        } else { // 字符长度判断
            isLong(value, setter, maxLength, msg);
        }
    }

    private void isEmpty(Supplier<String> getter, Consumer<String> setter,String msg) {
        String value = getter.get();
        if (StringUtils.isEmpty(value)) {
            setter.accept(msg + "不可为空");
            this.flag = false;
        }
    }

    //不为空时，判断长度
    private void isNotEmptyAndAdd(Supplier<String> getter, Consumer<String> setter,String msg, int maxLength) {
        String value = getter.get();
        if (StringUtils.isNotEmpty(value)) {
            isLong(value, setter, maxLength, msg);
        }
    }

    // 非空判断，并判断枚举值是否正确
    private <T extends Enum<T> & ObjectEnum> void isEmptyAndEnumAdd(Supplier<String> getter, Consumer<String> setter, String msg, Class<T> enumClass) {
        String value = getter.get();
        if (StringUtils.isEmpty(value)) {
            setter.accept(msg + "不可为空");
            this.flag = false;
        } else {
            isNotEmptyToEnum(getter, setter, msg, enumClass);
        }
    }

    // 不为空，判断枚举值是否正确
    private <T extends Enum<T> & ObjectEnum> void isNotEmptyToEnum(Supplier<String> getter, Consumer<String> setter, String msg, Class<T> enumClass) {
        String value = getter.get();
        if (!StringUtils.isEmpty(value)) {
            boolean isValid = false;
            for (T enumValue : enumClass.getEnumConstants()) {
                if (Objects.equals(enumValue.getValue(), value)) {
                    isValid = true;
                    break;
                }
            }
            if (!isValid) {
                setter.accept(msg + "请使用规范标识填写表格");
                this.flag = false;
            }
        }
    }

    // 非空判断，并判断枚举值是否正确
    private <T extends Enum<T> & BaseBoolValEnum> void isEmptyAndBoolEnumAdd(Supplier<String> getter, Consumer<String> setter, String msg, Class<T> enumClass) {
        String value = getter.get();
        if (StringUtils.isEmpty(value)) {
            setter.accept(msg + "不可为空");
            this.flag = false;
        } else {
            isNotEmptyToBoolEnum(getter, setter, msg, enumClass);
        }
    }

    // 不为空，判断枚举值是否正确
    private <T extends Enum<T> & BaseBoolValEnum> void isNotEmptyToBoolEnum(Supplier<String> getter, Consumer<String> setter, String msg, Class<T> enumClass) {
        String value = getter.get();
        if (!StringUtils.isEmpty(value)) {
            boolean isValid = false;
            for (BaseBoolValEnum enumValue : enumClass.getEnumConstants()) {
                if (Objects.equals(enumValue.getDesc(), value)) {
                    isValid = true;
                    break;
                }
            }
            if (!isValid) {
                setter.accept(msg + "请使用规范标识填写表格");
                this.flag = false;
            }
        }
    }

    // 非空时判断字符串是否可以转换为Double，并判断整数位与小数位是否符合长度要求
    private void isEmptyAndDoubleAdd(Supplier<String> getter, Consumer<String> setter, String msg, int integerLength, int decimalLength) {
        String value = getter.get();
        if (StringUtils.isNotEmpty(value)) {
            // 判断是否可以转换
            try {
                Double d = Double.parseDouble(value);
                if (d < Double.parseDouble(ZERO)) {
                    setter.accept(msg + "必须大于0");
                } else {
                    // 处理科学计数法,保留小数点后四位
                    DecimalFormat decimalFormat = new DecimalFormat("#.####");
                    String valueString = decimalFormat.format(d);

                    String[] split = valueString.split("\\.");
                    // 获取小数点前的位数
                    int integerPartLength = split[0].length();
                    // 获取小数点后的位数
                    int fractionalPartLength = 0;
                    if (split.length > 2) {
                        fractionalPartLength = split[1].length();
                    }

                    if (integerPartLength > integerLength || fractionalPartLength > decimalLength) {
                        setter.accept(msg + "长度不合法，总长度不超过8位，小数点后不超过3位");
                    }
                }
            } catch (NumberFormatException e) {
                setter.accept(msg + "必须为数字");
                this.flag = false;
            }

        }
    }
    // 判断字符串长度是否过长
    private void isLong(String value, Consumer<String> setter, int maxLength, String msg) {
        if (value.length() > maxLength) {
            setter.accept(msg + "长度不能超过" + maxLength + "个字符");
            this.flag = false;
        }
    }
    // 结果数据生成
    private String setResult(String result, String value) {
        if (StringUtils.isEmpty(result)) {
            return value;
        } else {
            return result + "," + value;
        }
    }

    /**
     * 每解析一行都会回调invoke()方法
     *
     * @param data    读取后的数据对象
     * @param context 内容
     */
    @Override
    public void invoke(PartsImportExcelVO data, AnalysisContext context) {

//        一，必须存在且合理
        isEmptyAndAdd(data::getGoodsId, data::setResult, setResult(data.getResult(), "物料编号"), 32);
        isEmptyAndAdd(data::getName, data::setResult, setResult(data.getResult(), "物料名称"), 64);
        isEmptyAndEnumAdd(data::getCategory, data::setResult, setResult(data.getResult(), "分类"), CategoryEnum.class);
        isNotEmptyAndAdd(data::getCategory, data::setResult, setResult(data.getResult(), "分类"),32);

//        二，分类，必须存在
        if (data.getCategory() != null ) {
            if (!CategoryEnum.OTHER.getValue().equals(data.getCategory())) { // 不为其他
                isEmpty(data::getUnit, data::setResult, setResult(data.getResult(), "单位"));
                if (CategoryEnum.EDGING.getValue().equals(data.getCategory())) { // 为封边
                    isEmpty(data::getColor, data::setResult, setResult(data.getResult(), "颜色"));
                    isEmpty(data::getWidth, data::setResult, setResult(data.getResult(), "宽度"));
                    isEmpty(data::getThickness, data::setResult, setResult(data.getResult(), "厚度"));
                }
            }
        }

//        三，存在则判断是否符合
        isEmptyAndBoolEnumAdd(data::getIsComposite, data::setResult, setResult(data.getResult(), "是否复合部件"), WhetherEnum.class);
        isNotEmptyAndAdd(data::getType, data::setResult, setResult(data.getResult(), "子类型"), 64);
        isNotEmptyAndAdd(data::getModel, data::setResult, setResult(data.getResult(), "型号"), 64);
        isNotEmptyAndAdd(data::getColor, data::setResult, setResult(data.getResult(), "颜色"), 64);
        isNotEmptyAndAdd(data::getMaterial, data::setResult, setResult(data.getResult(), "材质"), 64);
        isNotEmptyAndAdd(data::getUnit, data::setResult, setResult(data.getResult(), "单位"), 32);
        isNotEmptyAndAdd(data::getSpec, data::setResult, setResult(data.getResult(), "规格"), 64);
        isNotEmptyAndAdd(data::getBrand, data::setResult, setResult(data.getResult(), "品牌"), 64);
        isNotEmptyAndAdd(data::getFactor, data::setResult, setResult(data.getResult(), "厂家"), 128);
        isEmptyAndDoubleAdd(data::getLength, data::setResult, setResult(data.getResult(), "长度"), 5 , 3);
        isEmptyAndDoubleAdd(data::getWidth, data::setResult, setResult(data.getResult(), "宽度"), 5 , 3);
        isEmptyAndDoubleAdd(data::getThickness, data::setResult, setResult(data.getResult(), "厚度"), 5 , 3);
        isNotEmptyAndAdd(data::getRemark, data::setResult, setResult(data.getResult(), "备注"), 255);

        // 当为封边的时候，一定需要
//        if (StringUtils.isNotEmpty(data.getCategory())) {
//            if (data.getCategory().equals(CategoryEnum.EDGING.getValue())) {
//                isEmpty(data::getThickness, data::setResult, setResult(data.getResult(), "厚度"));
//                isEmpty(data::getWidth, data::setResult, setResult(data.getResult(), "宽度"));
//            }
//        }

        if (data.getResult() != null)
            data.setResult(data.getResult().replace("null,", ""));
        valueMap.put(context.getCurrentRowNum(), data.getResult());
        datas.add(data);
    }

    /**
     * 读取完后操作
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (this.flag)
            log.info("PlateExcelListener 所有数据读取完成");
    }

    /**
     * 返回数据
     *
     * @return 返回读取的数据集合
     **/
    public List<PartsImportExcelVO> getDates() {
        return datas;
    }

    /**
     * 返回读取结果
     *
     * @return 是否读取成功
     **/
    public boolean getFlag() {
        return flag;
    }

    /**
     * 返回错误信息
     *
     * @return String
     **/
    public Map<Integer, String> getValueMap() {
        return valueMap;
    }
}
