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.PmMidSlabAddvBtService;
import com.xisc.pm.domain.entity.PmMidSlabAddvBt;
import com.xisc.pm.domain.repository.PmMidSlabAddvBtRepository;
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.collections4.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 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/25 14:32
 */
@Slf4j
@ImportValidators({@ImportValidator(templateCode = "PM.MID_SLAB_ADDV_BT")})
public class PmMidSlabAddvBtValidator extends BatchValidatorHandler {

    private final ObjectMapper objectMapper;

    private final PmMidSlabAddvBtRepository pmMidSlabAddvBtRepository;

    private final PmMidSlabAddvBtService pmMidSlabAddvBtService;

    public PmMidSlabAddvBtValidator(ObjectMapper objectMapper, PmMidSlabAddvBtRepository pmMidSlabAddvBtRepository,
                                    PmMidSlabAddvBtService pmMidSlabAddvBtService) {
        this.objectMapper = objectMapper;
        this.pmMidSlabAddvBtRepository = pmMidSlabAddvBtRepository;
        this.pmMidSlabAddvBtService = pmMidSlabAddvBtService;
    }

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

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

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

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

        // 如果集合为空，则结束
        if (CollectionUtils.isEmpty(list)) {
            return flag;
        }

        // a)	单条记录中，“钢板厚度起”必须小于“钢板厚度止”；
        list.forEach(item -> {
            if (item.getPlateThickFrom() != null && item.getPlateThickTo() != null &&
                    item.getPlateThickFrom().compareTo(item.getPlateThickTo()) >= 0) {
                throw new CommonException("pm.plate_spec_bt_001", item.getPlateThickFrom(), item.getPlateThickTo());
            }
        });
        //b)	唯一性索引：轧制产线号、内部钢种、标准牌号、钢板厚度起止区间。更新/插入一条记录时，在非区间索引相同的情况下
        // ，钢板厚度起止区间不能存在交集，否则更新/插入失败。
        // 新增记录之间校验区间是否交叉-其他条件相同时，判断钢板厚度
        Map<String, List<PmMidSlabAddvBt>> plateThickKeyMap = list.stream().collect(Collectors.groupingBy(pmMidSlabAddvBtService::getPlateFromKey));
        for (Map.Entry<String, List<PmMidSlabAddvBt>> entry : plateThickKeyMap.entrySet()) {
            List<PmMidSlabAddvBt> slabAddvBtList = entry.getValue();
            // 新增记录之间校验区间是否交叉
            for (int i = 0; i < slabAddvBtList.size() - 1; i++) {
                for (int j = i + 1; j < slabAddvBtList.size(); j++) {
                    // 检查钢板厚度区间是否交叉
                    boolean plateThickIntervalCheck = Utils.isIntersect(slabAddvBtList.get(i).getPlateThickFrom(),
                            slabAddvBtList.get(i).getPlateThickTo(), slabAddvBtList.get(j).getPlateThickFrom(),
                            slabAddvBtList.get(j).getPlateThickTo());
                    if (plateThickIntervalCheck) {
                        addErrorMsg(idxMap.get(slabAddvBtList.get(i)), MessageAccessor.getMessage("pm.cut_place_bt_004",
                                new Object[]{slabAddvBtList.get(j).getPlateThickFrom(),
                                        slabAddvBtList.get(j).getPlateThickTo()}).getDesc());
                        flag = false;
                    }
                }
            }
        }

        // 与数据库记录校验区间是否交叉
        List<String> sgSignList = list.stream().map(PmMidSlabAddvBt::getSgSign).distinct().collect(Collectors.toList());
        List<String> rollLineNoList = list.stream().map(PmMidSlabAddvBt::getRollLineNo).distinct().collect(Collectors.toList());
        List<String> stNoList = list.stream().map(PmMidSlabAddvBt::getStNo).distinct().collect(Collectors.toList());
        List<PmMidSlabAddvBt> existPmMidSlabAddvBtList = pmMidSlabAddvBtRepository.selectByCondition(Condition.builder(PmMidSlabAddvBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmMidSlabAddvBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmMidSlabAddvBt.FIELD_SG_SIGN, sgSignList))
                .andWhere(Sqls.custom().andIn(PmMidSlabAddvBt.FIELD_ST_NO, stNoList))
                .andWhere(Sqls.custom().andIn(PmMidSlabAddvBt.FIELD_ROLL_LINE_NO, rollLineNoList))
                .build());
        if (CollectionUtils.isNotEmpty(existPmMidSlabAddvBtList)) {
            Map<String, List<PmMidSlabAddvBt>> existPlateThickKeyMap = existPmMidSlabAddvBtList.stream().collect(Collectors.groupingBy(pmMidSlabAddvBtService::getPlateFromKey));
            for (int i = 0; i < list.size(); i++) {
                // 如果数据库数据存在该条记录，则判断区间是否交叉
                if (existPlateThickKeyMap.containsKey(pmMidSlabAddvBtService.getPlateFromKey(list.get(i)))) {
                    List<PmMidSlabAddvBt> midSlabAddvBtList = existPlateThickKeyMap.get(pmMidSlabAddvBtService.getPlateFromKey(list.get(i)));
                    for (PmMidSlabAddvBt slabAddvBt : midSlabAddvBtList) {
                        // 检查钢板厚度区间是否交叉
                        boolean slabThickIntervalCheck = Utils.isIntersect(list.get(i).getPlateThickFrom(),
                                list.get(i).getPlateThickTo(), slabAddvBt.getPlateThickFrom(),
                                slabAddvBt.getPlateThickTo());
                        if (slabThickIntervalCheck) {

                            addErrorMsg(i, MessageAccessor.getMessage("pm.cut_place_bt_001",
                                    new Object[]{slabAddvBt.getPlateThickFrom(), slabAddvBt.getPlateThickTo()}).getDesc());
                            flag = false;
                        }
                    }
                }
            }
        }
        return flag;
    }
}
