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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xisc.pm.domain.entity.PmSlabReplBt;
import com.xisc.pm.domain.repository.PmSlabReplBtRepository;
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.function.Function;
import java.util.stream.Collectors;

/**
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024/7/26 10:15
 */
@Slf4j
@ImportValidators({@ImportValidator(templateCode = "PM.SLAB_REPL_BT")})
public class PmSlabReplBtValidator extends BatchValidatorHandler {

    private final ObjectMapper objectMapper;

    private final PmSlabReplBtRepository pmSlabReplBtRepository;

    public PmSlabReplBtValidator(ObjectMapper objectMapper, PmSlabReplBtRepository pmSlabReplBtRepository) {
        this.objectMapper = objectMapper;
        this.pmSlabReplBtRepository = pmSlabReplBtRepository;
    }


    @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<PmSlabReplBt> list = new ArrayList<>(data.size());
        Map<PmSlabReplBt, Integer> idxMap = new HashMap<>(data.size());

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

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

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

        // a.	唯一性索引：以优充次顺序码、当前出钢记号
        //b.	唯一性索引：当前出钢记号、替代出钢记号
        Map<String, List<PmSlabReplBt>> slabMap = list.stream().collect(Collectors
                .groupingBy(pmSlabReplBt -> pmSlabReplBt.getBetterToWorseSeq() + pmSlabReplBt.getCurStNo()));
        Map<String, List<PmSlabReplBt>> relMap = list.stream().collect(Collectors
                .groupingBy(pmSlabReplBt -> pmSlabReplBt.getCurStNo() + pmSlabReplBt.getReplStNo()));

        for (int i = 0; i < list.size(); i++) {
            if (slabMap.get(list.get(i).getBetterToWorseSeq() + list.get(i).getCurStNo()).size() > 1) {
                addErrorMsg(i, MessageAccessor.getMessage("pm.slab_repl_bt_001",
                        new Object[]{list.get(i).getBetterToWorseSeq(), list.get(i).getCurStNo()}).getDesc());
                flag = false;
            }
            if (relMap.get(list.get(i).getCurStNo() + list.get(i).getReplStNo()).size() > 1) {
                addErrorMsg(i, MessageAccessor.getMessage("pm.slab_repl_bt_002",
                        new Object[]{list.get(i).getCurStNo(), list.get(i).getReplStNo()}).getDesc());
                flag = false;
            }
        }


        List<Long> betterSeqList = list.stream().map(PmSlabReplBt::getBetterToWorseSeq).distinct().collect(Collectors.toList());
        List<String> curStNoList = list.stream().map(PmSlabReplBt::getCurStNo).distinct().collect(Collectors.toList());
        List<String> replStNoList = list.stream().map(PmSlabReplBt::getReplStNo).distinct().collect(Collectors.toList());
        List<Long> idList = list.stream().filter(item -> item.getPsrbId() != null).map(PmSlabReplBt::getPsrbId).collect(Collectors.toList());
        List<PmSlabReplBt> existSlabReplBtList = pmSlabReplBtRepository.selectByCondition(Condition.builder(PmSlabReplBt.class)
                .andWhere(Sqls.custom().andIn(PmSlabReplBt.FIELD_BETTER_TO_WORSE_SEQ, betterSeqList))
                .andWhere(Sqls.custom().andIn(PmSlabReplBt.FIELD_CUR_ST_NO, curStNoList))
                .andWhere(Sqls.custom().andEqualTo(PmSlabReplBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andNotIn(PmSlabReplBt.FIELD_PSRB_ID, idList, true))
                .build());
        if (CollectionUtils.isNotEmpty(existSlabReplBtList)) {
            Map<String, PmSlabReplBt> existSlabMap = existSlabReplBtList.stream().collect(Collectors
                    .toMap(pmSlabReplBt -> pmSlabReplBt.getBetterToWorseSeq() + pmSlabReplBt.getCurStNo(), Function.identity(), (k, v)->k));
            for (int i = 0; i < list.size(); i++) {
                if (existSlabMap.containsKey(list.get(i).getBetterToWorseSeq() + list.get(i).getCurStNo())) {
                    PmSlabReplBt slabRelBt = existSlabMap.get(list.get(i).getBetterToWorseSeq() + list.get(i).getCurStNo());
                    addErrorMsg(i, MessageAccessor.getMessage("pm.slab_repl_bt_003",
                            new Object[]{ slabRelBt.getBetterToWorseSeq(), slabRelBt.getCurStNo()}).getDesc());
                    flag = false;
                }
            }
        }

        List<PmSlabReplBt> existRelSlabReplBtList = pmSlabReplBtRepository.selectByCondition(Condition.builder(PmSlabReplBt.class)
                .andWhere(Sqls.custom().andIn(PmSlabReplBt.FIELD_CUR_ST_NO, curStNoList))
                .andWhere(Sqls.custom().andIn(PmSlabReplBt.FIELD_REPL_ST_NO, replStNoList))
                .andWhere(Sqls.custom().andEqualTo(PmSlabReplBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andNotIn(PmSlabReplBt.FIELD_PSRB_ID, idList, true))
                .build());
        if (CollectionUtils.isNotEmpty(existRelSlabReplBtList)) {
            Map<String, PmSlabReplBt> existRelMap = existRelSlabReplBtList.stream().collect(Collectors
                    .toMap(pmSlabReplBt -> pmSlabReplBt.getCurStNo() + pmSlabReplBt.getReplStNo(), Function.identity(), (k,v)->k));
            for (int i = 0; i < list.size(); i++) {
                if (existRelMap.containsKey(list.get(i).getCurStNo() + list.get(i).getReplStNo())) {
                    PmSlabReplBt slabRelBt = existRelMap.get(list.get(i).getCurStNo() + list.get(i).getReplStNo());
                    addErrorMsg(i, MessageAccessor.getMessage("pm.slab_repl_bt_004",
                            new Object[]{ slabRelBt.getCurStNo(), slabRelBt.getReplStNo()}).getDesc());
                    flag = false;
                }
            }
        }


        return flag;
    }
}
