package com.xisc.pm.app.service.validator;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xisc.pm.app.service.PmThickAddvBtService;
import com.xisc.pm.domain.entity.PmThickAddvBt;
import com.xisc.pm.domain.repository.PmThickAddvBtRepository;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.exception.CommonException;
import io.choerodon.core.oauth.DetailsHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.hzero.boot.imported.app.service.BatchValidatorHandler;
import org.hzero.boot.imported.infra.validator.annotation.ImportValidator;
import org.hzero.boot.imported.infra.validator.annotation.ImportValidators;
import org.hzero.core.message.MessageAccessor;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024/9/23 18:09
 */
@Slf4j
@ImportValidators({@ImportValidator(templateCode = "PM.THICK_ADDV_BT")})
public class PmThickAddvBtValidator extends BatchValidatorHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private PmThickAddvBtService pmThickAddvBtService;

    @Autowired
    private PmThickAddvBtRepository pmThickAddvBtRepository;


    @Override
    public boolean validate(List<String> data) {
        if (CollectionUtils.isEmpty(data)) {
            throw new CommonException("pm.import_data_is_empty_list");
        }
        Long tenantId = 0L;
        boolean flag = true;
        if (DetailsHelper.getUserDetails() != null && DetailsHelper.getUserDetails().getTenantId() != null) {
            tenantId = DetailsHelper.getUserDetails().getTenantId();
        }
        List<PmThickAddvBt> list = new ArrayList<>(data.size());
        Map<PmThickAddvBt, Integer> idxMap = new HashMap<>(data.size());

        for (int i = 0; i < data.size(); i++) {
            try {
                // 转换对象
                PmThickAddvBt pmThickAddvBt = objectMapper.readValue(data.get(i), PmThickAddvBt.class);
                pmThickAddvBt.setTenantId(tenantId);

                Integer integer = idxMap.putIfAbsent(pmThickAddvBt, i);
                if (integer != null && integer != i) {
                    // 重复数据
                    addErrorMsg(i, MessageAccessor.getMessage("pm.exist_same_data").getDesc());
                    continue;
                }

                list.add(pmThickAddvBt);
            } catch (JsonProcessingException e) {
                log.error(e.getMessage(), e);
            }
        }

        // 如果集合为空，则结束
        if (CollectionUtils.isEmpty(list)) {
            return flag;
        }
        for (int i = 0; i < list.size(); i++) {
            //单条记录中，“钢板厚度起”必须小于“钢板厚度止”；
            if (list.get(i).getPlateThickFrom().compareTo(list.get(i).getPlateThickTo()) >= 0) {
                addErrorMsg(i, MessageAccessor.getMessage("pm.thick_addv_bt_001",
                        new Object[]{list.get(i).getPlateThickFrom(), list.get(i).getPlateThickTo()}).getDesc());
            }
            //单条记录中，“组合板宽度起”必须小于“组合板宽度止
            if (list.get(i).getCombinePlateWidthFrom().compareTo(list.get(i).getCombinePlateWidthTo()) >= 0) {
                addErrorMsg(i, MessageAccessor.getMessage("pm.thick_addv_bt_002",
                        new Object[]{list.get(i).getCombinePlateWidthFrom(), list.get(i).getCombinePlateWidthTo()}).getDesc());
            }
        }

        // 新增记录之间校验区间是否交叉
        Map<String, List<PmThickAddvBt>> thickAddvMap = list.stream().collect(Collectors.groupingBy(pmThickAddvBtService::getPlateKey));
        for (Map.Entry<String, List<PmThickAddvBt>> entry : thickAddvMap.entrySet()) {
            List<PmThickAddvBt> valueList = entry.getValue();
            for (int i = 0; i < valueList.size(); i++) {
                for (int j = 0; j < valueList.size(); j++) {
                    if (i == j) {
                        continue;
                    }
                    // 校验板坯厚度区间是否交叉
                    boolean slabThickIntervalCheck = Utils.isIntersect(valueList.get(i).getPlateThickFrom(), valueList.get(i).getPlateThickTo(),
                            valueList.get(j).getPlateThickFrom(), valueList.get(j).getPlateThickTo());
                    if (!slabThickIntervalCheck) {
                        continue;
                    }

                    // 校验板坯宽度区间是否交叉
                    boolean slabWidthIntervalCheck = Utils.isIntersect(valueList.get(i).getCombinePlateWidthFrom(), valueList.get(i).getCombinePlateWidthTo(),
                            valueList.get(j).getCombinePlateWidthFrom(), valueList.get(j).getCombinePlateWidthTo());
                    if (!slabWidthIntervalCheck) {
                        continue;
                    }

                    addErrorMsg(idxMap.get(valueList.get(i)), MessageAccessor.getMessage("pm.thick_addv_bt_003",
                            new Object[]{valueList.get(j).getPlateThickFrom(), valueList.get(j).getPlateThickTo(),
                                    valueList.get(j).getCombinePlateWidthFrom(), valueList.get(j).getCombinePlateWidthTo()}).getDesc());

                    flag = false;
                }
            }
        }

        // 获取字段集合，查询数据库该范围内数据
        List<String> toleTypeList = list.stream().map(PmThickAddvBt::getTolTypeCode).distinct().collect(Collectors.toList());
        List<String> wholeHeatTreatmentTypeList = list.stream().map(PmThickAddvBt::getWholeHeatTreatmentType).distinct().collect(Collectors.toList());
        List<String> mscLineNoList = list.stream().map(PmThickAddvBt::getMscLineNo).distinct().collect(Collectors.toList());
        List<BigDecimal> thickAddvList = list.stream().map(PmThickAddvBt::getThickAddv).distinct().collect(Collectors.toList());
        List<PmThickAddvBt> existList = pmThickAddvBtRepository.selectByCondition(Condition.builder(PmThickAddvBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmThickAddvBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmThickAddvBt.FIELD_TOL_TYPE_CODE, toleTypeList))
                .andWhere(Sqls.custom().andIn(PmThickAddvBt.FIELD_WHOLE_HEAT_TREATMENT_TYPE, wholeHeatTreatmentTypeList))
                .andWhere(Sqls.custom().andIn(PmThickAddvBt.FIELD_MSC_LINE_NO, mscLineNoList))
                .andWhere(Sqls.custom().andIn(PmThickAddvBt.FIELD_THICK_ADDV, thickAddvList))
                .build());

        // 与数据库记录校验区间是否交叉
        if (CollectionUtils.isNotEmpty(existList)) {
            // 校验
            Map<String, List<PmThickAddvBt>> existSlabBtMap = existList.stream().collect(Collectors.groupingBy(pmThickAddvBtService::getPlateKey));
            for (int i = 0; i < list.size(); i++) {
                if (existSlabBtMap.containsKey(pmThickAddvBtService.getPlateKey(list.get(i)))) {
                    List<PmThickAddvBt> pmThickAddvBtValueList = existSlabBtMap.get(pmThickAddvBtService.getPlateKey(list.get(i)));
                    for (PmThickAddvBt addvBt : pmThickAddvBtValueList) {
                        // 校验钢板厚度区间是否交叉
                        boolean slabThickIntervalCheck = Utils.isIntersect(list.get(i).getPlateThickFrom()
                                , list.get(i).getPlateThickTo(), addvBt.getPlateThickFrom(), addvBt.getPlateThickTo());
                        if (!slabThickIntervalCheck) {
                            continue;
                        }

                        // 组合板宽度起区间是否交叉
                        boolean slabWidthIntervalCheck = Utils.isIntersect(list.get(i).getCombinePlateWidthFrom()
                                , list.get(i).getCombinePlateWidthTo(), addvBt.getCombinePlateWidthFrom(), addvBt.getCombinePlateWidthTo());
                        if (!slabWidthIntervalCheck) {
                            continue;
                        }

                        addErrorMsg(i, MessageAccessor.getMessage("pm.thick_addv_bt_004",
                                new Object[]{addvBt.getPlateThickFrom(), addvBt.getPlateThickTo(),
                                        addvBt.getCombinePlateWidthFrom(), addvBt.getCombinePlateWidthTo()}).getDesc());
                        flag = false;
                    }
                }

            }
        }
        return flag;
    }
}
