package com.yeejoin.amos.boot.module.jg.biz.config;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.module.jg.api.dto.EquipInfoCylinderExcelDto;
import com.yeejoin.amos.boot.module.jg.biz.dao.ESEquipmentCategory;
import com.yeejoin.amos.boot.module.jg.biz.service.*;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.*;
import com.yeejoin.amos.boot.module.ymt.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.mapper.CategoryOtherInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.RegistrationInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.SuperviseInfoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static com.alibaba.fastjson.JSON.toJSONString;

@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
@Component
public class PressureVesselListener extends AnalysisEventListener<EquipInfoCylinderExcelDto> {
    private static final int BATCH_COUNT = 1000;
    //数据集合
    List<String> useInnerCodeList = new ArrayList<>();//单位内部编号集合
    List<String> equCodeList = new ArrayList<>();//设备代码集合
    List<String> records = new ArrayList<>();//设备代码集合
    List<String> factoryNumList = new ArrayList<>();//出厂编码集合
    List<IdxBizJgUseInfo> useInfoList = new ArrayList<>();
    List<IdxBizJgRegisterInfo> registerInfoList = new ArrayList<>();
    List<IdxBizJgDesignInfo> designInfoList = new ArrayList<>();
    List<IdxBizJgFactoryInfo> factoryInfoList = new ArrayList<>();
    List<IdxBizJgTechParamsVessel> paramsVesselList = new ArrayList<>();
    List<IdxBizJgInspectionDetectionInfo> inspectionDetectionInfoList = new ArrayList<>();
    List<ESEquipmentCategoryDto> esEquipmentCategoryList = new ArrayList<>();
    private StringBuilder result = new StringBuilder();
    private JgInstallationNoticeServiceImpl jgInstallationNoticeService;
    private IIdxBizJgUseInfoService idxBizJgUseInfoService;
    private IdxBizJgDesignInfoServiceImpl idxBizJgDesignInfoService;
    private IdxBizJgFactoryInfoServiceImpl idxBizJgFactoryInfoService;
    private IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoService;
    private IdxBizJgTechParamsVesselServiceImpl idxBizJgTechParamsVesselService;
    private IdxBizJgInspectionDetectionInfoServiceImpl idxBizJgInspectionDetectionInfoService;
    private ICommonService commonService;
    private RegistrationInfoMapper tzsJgRegistrationInfoMapper;
    private ESEquipmentCategory esEquipmentCategory;
    private CategoryOtherInfoMapper categoryOtherInfoMapper;
    private SuperviseInfoMapper superviseInfoMapper;
    private Map<String, Object> paramMap;
    private CompanyBo company;

    @Override
    public void invoke(EquipInfoCylinderExcelDto data, AnalysisContext context) {
        ReadRowHolder readRowHolder = context.readRowHolder();
        int rowIndex = readRowHolder.getRowIndex() + 1;
        try {
            log.info("解析第{}行数据：{}", rowIndex, JSON.toJSONString(data));
            // 检查各字段是否为空，如果为空则追加错误信息
            checkNotBlank(data.getProductName(), "设备名称不能为空");
            checkNotBlank(data.getBrandName(), "品牌名称不能为空");
            checkNotBlank(data.getEquType(), "设备型号不能为空");
            checkNotBlank(data.getUseInnerCode(), "单位内部编号不能为空");
            if (useInnerCodeList.contains(data.getUseInnerCode())) {
                result.append("单位内部编号不能重复；");
            }
            checkNotBlank(data.getWhetherVehicleCylinder(), "是否车用气瓶不能为空");
            checkNotBlank(data.getEquCodeType(), "是否有设备代码不能为空");
            checkNotBlank(data.getEquCode(), "设备代码不能为空");
            if ("1".equals(data.getEquCodeType()) && equCodeList.contains(data.getEquCode())) {
                result.append("设备代码不能重复；");
            }
            this.checkEquCodeUniqueness(data.getEquCode());
            checkNotBlank(data.getDesignUnitCreditCode(), "设计单位统一社会信用代码不能为空");
            checkNotBlank(data.getDesignUnitName(), "设计单位名称不能为空");
            Optional.ofNullable(data.getDesignDate()).ifPresent(v -> checkDateFormatCorrect(v, "设计日期格式不正确"));
            Optional.ofNullable(data.getAppraisalDate()).ifPresent(v -> checkDateFormatCorrect(v, "设计文件鉴定日期格式不正确"));
            checkNotBlank(data.getProduceUnitCreditCode(), "制造单位统一社会信用代码不能为空");
            checkNotBlank(data.getProduceUnitName(), "制造单位名称不能为空");
            checkNotBlank(data.getProduceLicenseNum(), "制造许可编号不能为空");
            checkNotBlank(data.getFactoryNum(), "出厂编号/产品编码不能为空");
            if ("0".equals(data.getWhetherVehicleCylinder()) && factoryNumList.contains(data.getFactoryNum()))
                result.append("出厂编号/产品编码不能重复；");
            checkFactoryNumUniqueness(data.getFactoryNum(), null);
            checkNotBlank(data.getProduceDate(), "制造日期不能为空");
            checkDateFormatCorrect(data.getProduceDate(), "制造日期格式不正确");
            checkNotBlank(data.getInspectOrgName(), "检测机构名称不能为空");
            checkNotBlank(data.getInspectStaff(), "检测人员名称不能为空");
            checkNotBlank(data.getInspectDate(), "检测日期不能为空");
            checkDateFormatCorrect(data.getInspectDate(), "检测日期格式不正确");
            checkNotBlank(data.getSingleBottleVolume(), "单瓶容积不能为空");
            checkNotBlank(data.getChargingMedium(), "充装介质不能为空");
            checkNotBlank(data.getNominalWorkingPressure(), "公称工作压力不能为空");

            // 如果存在错误信息，则抛出 BadRequest 异常
            if (result.length() > 0) {
                result.insert(0, "Excel第[" + rowIndex + "]行 -> ");
                throw new BadRequest(result.toString());
            }
            this.dealExcelData(data);
        } catch (Exception e) {
            log.error(String.format("行索引数: [%s] -> 失败的 Excel 数据: [%s]", rowIndex, JSON.toJSONString(data)), e);
            throw e;
        }
    }

    private void checkEquCodeUniqueness(String equCode) {
        // 根据设备代码检查唯一性
        LambdaQueryWrapper<RegistrationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RegistrationInfo::getEquCode, equCode);
        Integer count = tzsJgRegistrationInfoMapper.selectCount(wrapper);
        if (count > 0) {
            result.append("设备代码系统中已存在");
        }
    }

    // 检查上传Excel中的日期格式是否正确
    private void checkDateFormatCorrect(String date, String errorMessage) {
        if (!date.matches("\\d{4}-\\d{2}-\\d{2}")) {
            result.append(errorMessage).append("；");
        }
    }

    // 检查字段是否为空，如果为空则追加错误信息到result
    private void checkNotBlank(String value, String errorMessage) {
        if (StringUtils.isBlank(value)) {
            result.append(errorMessage).append("；");
        }
    }

    private void checkFactoryNumUniqueness(String factoryNum, String sequenceNbr) {
        // 车用气瓶业务里面的 出厂编号/产品编码 校验唯一性（产品编号在车用气瓶范围内全局唯一）
        if (commonService.checkFactoryNumUniquenessForVehicleCylinder(factoryNum, sequenceNbr) > 0) {
            result.append("出厂编号/产品编码系统中已存在！");
        }
    }

    /**
     * 处理导入数据
     *
     * @param data excelData
     */
    private void dealExcelData(EquipInfoCylinderExcelDto data) {
        useInnerCodeList.add(data.getUseInnerCode());
        equCodeList.add(data.getEquCode());
        factoryNumList.add("0".equals(data.getWhetherVehicleCylinder()) ? data.getFactoryNum() : null);

        Date date = new Date();
        String record = UUID.randomUUID().toString();
        records.add(record);

        //使用信息
        IdxBizJgUseInfo useInfo = new IdxBizJgUseInfo();
        BeanUtils.copyProperties(data, useInfo);
        useInfo.setRecord(record);
        useInfo.setRecDate(date);
        useInfo.setDataSource("jg");
        useInfo.setEquState(null);
        useInfoList.add(useInfo);

        //设计信息
        IdxBizJgDesignInfo designInfo = new IdxBizJgDesignInfo();
        BeanUtils.copyProperties(data, designInfo);
        designInfo.setRecord(record);
        designInfo.setRecDate(date);
        designInfo.setDesignDate(DateUtil.parse(data.getDesignDate(), "yyyy-MM-dd"));
        designInfoList.add(designInfo);

        //制造信息
        IdxBizJgFactoryInfo factoryInfo = new IdxBizJgFactoryInfo();
        BeanUtils.copyProperties(data, factoryInfo);
        factoryInfo.setRecord(record);
        factoryInfo.setRecDate(date);
        factoryInfo.setProduceDate(DateUtil.parse(data.getProduceDate(), "yyyy-MM-dd"));
        factoryInfo.setImported(Optional.ofNullable(data.getImported()).orElse("0"));
        factoryInfoList.add(factoryInfo);

        //注册登记
        IdxBizJgRegisterInfo registerInfo = new IdxBizJgRegisterInfo();
        BeanUtils.copyProperties(data, registerInfo);
        registerInfo.setRecord(record);
        registerInfo.setRecDate(date);
        registerInfo.setEquCategory((String) paramMap.get("EQU_CATEGORY_CODE"));
        registerInfo.setEquDefine((String) paramMap.get("EQU_DEFINE_CODE"));
        registerInfo.setEquList((String) paramMap.get("EQU_LIST_CODE"));
        registerInfo.setRegisterState(idxBizJgRegisterInfoService.getRegCode());
        registerInfoList.add(registerInfo);

        //检验检测
        IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = new IdxBizJgInspectionDetectionInfo();
        BeanUtils.copyProperties(data, inspectionDetectionInfo);
        List<Map<String, Object>> InspectOrgList = commonService.getUnitListByType("inspection", "");
        inspectionDetectionInfo.setInspectOrgCode(findUseCode(InspectOrgList, data.getInspectOrgName()));
        inspectionDetectionInfo.setRecord(record);
        inspectionDetectionInfo.setRecDate(date);
        inspectionDetectionInfo.setInspectType("ZZJDJY");
        inspectionDetectionInfo.setInspectConclusion("6040");//默认合格
        inspectionDetectionInfo.setInspectDate(DateUtil.parse(data.getInspectDate(), "yyyy-MM-dd"));
        inspectionDetectionInfo.setNextInspectDate(Date.from(
                LocalDate.parse(data.getInspectDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))
                        .plusYears(3)
                        .atStartOfDay(ZoneId.systemDefault())
                        .toInstant()));
        inspectionDetectionInfoList.add(inspectionDetectionInfo);

        //技术参数
        IdxBizJgTechParamsVessel paramsVessel = new IdxBizJgTechParamsVessel();
        BeanUtils.copyProperties(data, paramsVessel);
        paramsVessel.setRecord(record);
        paramsVessel.setRecDate(date);
        paramsVesselList.add(paramsVessel);

        ESEquipmentCategoryDto dto = JSON.parseObject(toJSONString(data), ESEquipmentCategoryDto.class);
        // 使用单位信息
        dto.setDATA_SOURCE(useInfo.getDataSource());
        dto.setNEXT_INSPECT_DATE(inspectionDetectionInfo.getNextInspectDate() + "");
        dto.setREC_DATE(System.currentTimeMillis());
        dto.setSEQUENCE_NBR(record);
        dto.setFACTORY_NUM(factoryInfo.getFactoryNum());
        dto.setUSE_INNER_CODE(useInfo.getUseInnerCode());
        dto.setEQU_CATEGORY((String) paramMap.get("EQU_CATEGORY"));
        dto.setEQU_CATEGORY_CODE((String) paramMap.get("EQU_CATEGORY_CODE"));
        dto.setEQU_LIST((String) paramMap.get("EQU_LIST"));
        dto.setEQU_LIST_CODE((String) paramMap.get("EQU_LIST_CODE"));
        dto.setEQU_DEFINE((String) paramMap.get("EQU_DEFINE"));
        dto.setEQU_DEFINE_CODE((String) paramMap.get("EQU_DEFINE_CODE"));
        dto.setUSE_UNIT_CREDIT_CODE(company.getCompanyCode());
        dto.setUSE_UNIT_NAME(company.getCompanyName());
        esEquipmentCategoryList.add(dto);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (paramsVesselList.size() > BATCH_COUNT) {
            throw new BadRequest(result.append("单次导入限制1000条") + "");
        }
        if (!useInfoList.isEmpty()) {
            idxBizJgUseInfoService.saveBatch(useInfoList);
        }
        if (!designInfoList.isEmpty()) {
            idxBizJgDesignInfoService.saveBatch(designInfoList);
        }
        if (!registerInfoList.isEmpty()) {
            idxBizJgRegisterInfoService.saveBatch(registerInfoList);
        }
        if (!factoryInfoList.isEmpty()) {
            idxBizJgFactoryInfoService.saveBatch(factoryInfoList);
        }
        if (!paramsVesselList.isEmpty()) {
            idxBizJgTechParamsVesselService.saveBatch(paramsVesselList);
        }
        if (!inspectionDetectionInfoList.isEmpty()) {
            idxBizJgInspectionDetectionInfoService.saveBatch(inspectionDetectionInfoList);
        }
        if (!esEquipmentCategoryList.isEmpty()) {
            esEquipmentCategory.saveAll(esEquipmentCategoryList);
        }
        result.append("导入完成，成功导入");
        result.append(useInfoList.size());
        result.append("条数据");
        log.info("所有数据解析完成！");
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (!esEquipmentCategoryList.isEmpty()) {
            superviseInfoMapper.deleteDataAll(records);
            esEquipmentCategory.deleteAll(esEquipmentCategoryList);
        }
        throw exception;
    }

    public String getResult() {
        return result.toString();
    }

    public String findUseCode(List<Map<String, Object>> unitList, String inspectOrgName) {
        Optional<Map<String, Object>> optional = unitList.stream()
                .filter(map -> map.containsKey("useUnit") && map.get("useUnit").equals(inspectOrgName))
                .findFirst();
        return optional.map(map -> (String) map.get("useCode")).orElse(null);
    }
}