package com.cf.imes.module.executor.service.veneer;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.ListUtils;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerImportExcelVO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
import com.cf.imes.module.executor.enums.veneer.VeneerStatusEnum;
import com.cf.imes.module.executor.enums.veneer.VeneerProductLevelEnum;
import com.cf.imes.module.executor.util.fileConversion.admin.ToolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;

import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_DIGITAL_TYPE_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_LENGTH_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_NUMBER_LENGTH_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_ORG_CLASSIFICATION_NAME_NOT_EXIST;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_POSITIVE_NUMBER_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_REQUIRED_LACK;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_VENEER_NO_DUPLICATE;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_VENEER_NO_FORMAT_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_PRODUCT_LEVEL_ERROR;

/**
 * 贴皮excel导入 解析器
 *
 * @author Gqr
 * @since 2026/1/5 18:18
 */
@Slf4j
public class VeneerExcelListener extends AnalysisEventListener<VeneerImportExcelVO> {
    /**
     * 每500条操作入库一次
     */
    private static final int BATCH_COUNT = 500;
    private List<VeneerImportExcelVO> cachedInsertDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<VeneerImportExcelVO> cachedUpdateDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    private VeneerService veneerService;

    // 贴皮编号：id
    private Map<String, Long> orgVeneerNoMap;

    private Map<Integer, String> headMap;

    private Set<String> orgClassificationNameSet;
    /** 本次文件已出现的编号，避免同一文件内重复新增/更新。 */
    private final Set<String> importedVeneerNoSet = new HashSet<>();

    private Long organId;

    public VeneerExcelListener(VeneerService veneerService) {
        this.veneerService = veneerService;
        // 查询机构下所有的贴皮编号
        orgVeneerNoMap = veneerService.getOrgVeneerNo();
        organId = SecurityFrameworkUtils.getUserOrganId();
        List<VeneerClassificationNameRespVO> orgVeneerClassificationNameList = veneerService.getOrgVeneerClassificationNameList();
        orgClassificationNameSet = CollUtil.isNotEmpty(orgVeneerClassificationNameList)
                ? orgVeneerClassificationNameList.stream().map(VeneerClassificationNameRespVO::getName).collect(Collectors.toSet())
                : Collections.emptySet();
    }

    /**
     * 每解析一行都会回调invoke()方法
     *
     * @param data    读取后的数据对象
     * @param context 内容
     */
    @Override
    public void invoke(VeneerImportExcelVO data, AnalysisContext context) {
        // 获取行号，标题算一行+1
        ReadRowHolder readRowHolder = context.readRowHolder();
        int rowIndex = readRowHolder.getRowIndex() + 1;

        // 必填属性校验
        if (!data.validRequired()) {
            throw new ServiceException(VENEER_IMPORT_REQUIRED_LACK, rowIndex);
        }

        String veneerNo = data.getVeneerNo();

        // 与 VeneerSaveReqVO 的编号规则保持一致
        if (!veneerNo.matches("^[^\\\\/:*?\"，|<>]*$")) {
            throw new ServiceException(VENEER_IMPORT_VENEER_NO_FORMAT_ERROR, rowIndex, veneerNo);
        }
        if (!importedVeneerNoSet.add(veneerNo)) {
            throw new ServiceException(VENEER_IMPORT_VENEER_NO_DUPLICATE, rowIndex, veneerNo);
        }

        // @InEnum 在 Excel 导入场景不会自动触发，需显式校验
        if (!Arrays.stream(VeneerProductLevelEnum.values())
                .anyMatch(item -> item.getCode().equals(data.getProductLevel()))) {
            throw new ServiceException(VENEER_IMPORT_PRODUCT_LEVEL_ERROR, rowIndex, data.getProductLevel());
        }

        // 校验分类名称组织内是否存在
        validClassificationName(data.getClassificationName(), rowIndex);

        // 校验属性长度
        validFieldLength(headMap.get(0), veneerNo, 32, rowIndex);
        validFieldLength(headMap.get(1), data.getBatchNo(), 32, rowIndex);
        validFieldLength(headMap.get(3), data.getVeneerName(), 64, rowIndex);
        validFieldLength(headMap.get(5), data.getColor(), 32, rowIndex);
        validFieldLength(headMap.get(6), data.getMaterial(), 32, rowIndex);
        validFieldLength(headMap.get(10), data.getBrand(), 32, rowIndex);
        validFieldLength(headMap.get(11), data.getSpec(), 64, rowIndex);
        validFieldLength(headMap.get(12), data.getFactory(), 64, rowIndex);
        validFieldLength(headMap.get(14), data.getRemark(), 255, rowIndex);

        // 校验类型
        validPositiveFloatNumberSize(headMap.get(7), data.getLength(), Double.class, 4, 2, rowIndex);
        validPositiveFloatNumberSize(headMap.get(8), data.getWidth(), Double.class, 4, 2, rowIndex);
        validPositiveFloatNumberSize(headMap.get(9), data.getThickness(), Double.class, 4, 2, rowIndex);
        validPositiveIntegerSize(headMap.get(13), data.getNum(), 4, rowIndex);

        // 校验贴皮是新增还是更新
        Long existId = orgVeneerNoMap.get(veneerNo);
        if (ObjectUtil.isNotNull(existId)) {
            data.setId(existId);
            // 累计更新列表
            cachedUpdateDataList.add(data);

            // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
            if (cachedUpdateDataList.size() >= BATCH_COUNT) {
                updateData();
                // 存储完成清理 list
                cachedUpdateDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
            return;
        }

        // 累计新增列表
        cachedInsertDataList.add(data);

        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedInsertDataList.size() >= BATCH_COUNT) {
            insertData();
            // 存储完成清理 list
            cachedInsertDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        insertData();
        updateData();
        log.debug("所有数据解析完成！");
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        if (headMap == null || headMap.size() < 15
                || !headMap.keySet().containsAll(Arrays.asList(
                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14))) {
            throw new ServiceException(VENEER_IMPORT_REQUIRED_LACK, 1);
        }
        this.headMap = headMap;
    }

    /**
     * 批量新增贴皮
     */
    private void insertData() {
        log.debug("{}条数据，开始新增贴皮数据！", cachedInsertDataList.size());
        List<VeneerDO> veneerDOS = BeanUtil.copyToList(cachedInsertDataList, VeneerDO.class);
        for (VeneerDO veneerDO : veneerDOS) {
            veneerDO.setOrganId(organId);
            veneerDO.setDefect(false);
            veneerDO.setRemain(false);
            veneerDO.setStatus(VeneerStatusEnum.NOT_USE.getCode());
            veneerDO.setDeleted(false);
        }
        if (CollUtil.isNotEmpty(cachedInsertDataList)) {
            veneerService.batchInsert(veneerDOS);
        }
        log.debug("excel导入贴皮数据保存成功！");
    }

    /**
     * 批量更新贴皮
     */
    private void updateData() {
        log.debug("{}条数据，开始更新贴皮数据！", cachedUpdateDataList.size());
        if (CollUtil.isNotEmpty(cachedUpdateDataList)) {
            veneerService.batchUpdate(BeanUtil.copyToList(cachedUpdateDataList, VeneerDO.class));
        }
        log.debug("excel导入贴皮数据保存成功！");
    }

    /**
     * 校验组织内分类名称是否存在
     * @param classificationName
     */
    private void validClassificationName(String classificationName, int rowIndex) {
        if (!orgClassificationNameSet.contains(classificationName)) {
            throw new ServiceException(VENEER_IMPORT_ORG_CLASSIFICATION_NAME_NOT_EXIST, rowIndex, classificationName);
        }
    }

    /**
     * 校验长度
     *
     * @param key
     * @param val
     * @param length
     */
    private void validFieldLength(String key, String val, int length, int rowIndex) {
        if (StringUtils.isNotEmpty(val) && length < val.length()) {
            throw new ServiceException(VENEER_IMPORT_LENGTH_ERROR, rowIndex, key, length);
        }
    }


    /**
     * 检查值大于0、数据浮点类型和长度
     *
     * @param key
     * @param value
     * @param targetType
     * @param length
     * @param decimalLength
     * @param rowIndex
     */
    private void validPositiveFloatNumberSize(String key, String value, Class<?> targetType, Integer length, Integer decimalLength, int rowIndex) {
        if (StringUtils.isNotEmpty(value)) {
            if (Boolean.TRUE.equals(ToolUtil.convertToType(value, targetType))) {
                if (Boolean.TRUE.equals(checkPositiveNumber(value))) {
                    if (!ToolUtil.checkPrecision(value, length, decimalLength)) {
                        throw new ServiceException(VENEER_IMPORT_NUMBER_LENGTH_ERROR, rowIndex, key, length, decimalLength);
                    }
                } else {
                    throw new ServiceException(VENEER_IMPORT_POSITIVE_NUMBER_ERROR, rowIndex, key);
                }
            } else {
                throw new ServiceException(VENEER_IMPORT_DIGITAL_TYPE_ERROR, rowIndex, key);
            }
        }
    }

    /**
     * 检查值大于0、integer类型
     * @param key
     * @param value
     * @param rowIndex
     */
    private void validPositiveNumber(String key, String value, int rowIndex) {
        if (StringUtils.isNotEmpty(value)) {
            if (Boolean.TRUE.equals(ToolUtil.convertToType(value, Integer.class))) {
                if (Boolean.FALSE.equals(checkPositiveNumber(value))) {
                    throw new ServiceException(VENEER_IMPORT_POSITIVE_NUMBER_ERROR, rowIndex, key);
                }
            } else {
                throw new ServiceException(VENEER_IMPORT_DIGITAL_TYPE_ERROR, rowIndex, key);
            }
        }
    }

    private void validPositiveIntegerSize(String key, String value, int integerLength, int rowIndex) {
        validPositiveNumber(key, value, rowIndex);
        if (StringUtils.isNotEmpty(value) && !ToolUtil.checkPrecision(value, integerLength, 0)) {
            throw new ServiceException(VENEER_IMPORT_NUMBER_LENGTH_ERROR, rowIndex, key, integerLength, 0);
        }
    }

    /**
     * 检查是否正数（不包含0）
     *
     * @param numberStr
     * @return
     */
    public static Boolean checkPositiveNumber(String numberStr) {
        try {
            double number = Double.parseDouble(numberStr);
            // 进行正负判断
            return number > 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
