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

import com.xisc.pm.api.dto.PmPlateThickAddvBtDTO;
import com.xisc.pm.app.service.PmPlateThickAddvBtService;
import com.xisc.pm.domain.entity.PmPlateThickAddvBt;
import com.xisc.pm.domain.entity.PmPlateThickAddvBtTra;
import com.xisc.pm.domain.repository.PmPlateThickAddvBtRepository;
import com.xisc.pm.domain.repository.PmPlateThickAddvBtTraRepository;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.util.BeanUtils;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.domain.Page;
import io.choerodon.core.exception.CommonException;
import io.choerodon.core.oauth.DetailsHelper;
import io.choerodon.mybatis.pagehelper.PageHelper;
import io.choerodon.mybatis.pagehelper.domain.PageRequest;
import org.apache.commons.collections.CollectionUtils;
import org.hzero.boot.platform.lov.adapter.LovAdapter;
import org.hzero.boot.platform.lov.dto.LovValueDTO;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 钢板轧制规格及厚度余量基准表(PmPlateThickAddvBt)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-07-23 17:19:39
 */
@Service
public class PmPlateThickAddvBtServiceImpl implements PmPlateThickAddvBtService {

    private PmPlateThickAddvBtRepository pmPlateThickAddvBtRepository;

    private PmPlateThickAddvBtTraRepository pmPlateThickAddvBtTraRepository;

    private LovAdapter lovAdapter;

    public PmPlateThickAddvBtServiceImpl(PmPlateThickAddvBtRepository pmPlateThickAddvBtRepository, PmPlateThickAddvBtTraRepository pmPlateThickAddvBtTraRepository, LovAdapter lovAdapter) {
        this.pmPlateThickAddvBtRepository = pmPlateThickAddvBtRepository;
        this.pmPlateThickAddvBtTraRepository = pmPlateThickAddvBtTraRepository;
        this.lovAdapter = lovAdapter;
    }

    @Override
    public Page<PmPlateThickAddvBt> selectList(PageRequest pageRequest, PmPlateThickAddvBt pmPlateThickAddvBt) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmPlateThickAddvBtRepository.selectList(pmPlateThickAddvBt));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveData(Long tenantId, List<PmPlateThickAddvBt> pmPlateThickAddvBtList) {
        // 检查数据列表是否为空，如果为空则直接返回
        if (CollectionUtils.isEmpty(pmPlateThickAddvBtList)) {
            return;
        }
        // 新增记录之间校验区间是否交叉
        checkNewAddOrUpdateDataInterval(pmPlateThickAddvBtList);
        // 与数据库记录校验区间是否交叉
        checkExistDataIntervalByDb(tenantId, pmPlateThickAddvBtList);

        // 获取当前时间及操作人信息
        Date now = new Date();
        String username = DetailsHelper.getUserDetails().getUsername();
        List<PmPlateThickAddvBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmPlateThickAddvBtList.size());

        // 分离需要插入和更新的列表
        List<PmPlateThickAddvBt> insertList = pmPlateThickAddvBtList.stream().filter(line -> line.getPptabId() == null).collect(Collectors.toList());
        List<PmPlateThickAddvBt> updateList = pmPlateThickAddvBtList.stream().filter(line -> line.getPptabId() != null).collect(Collectors.toList());

        // 记录历史表
        for (PmPlateThickAddvBt pmPlateThickAddvBt : updateList) {
            PmPlateThickAddvBtTra pmPlateThickAddvBtTra = new PmPlateThickAddvBtTra();
            BeanUtils.copy(pmPlateThickAddvBt, pmPlateThickAddvBtTra);

            // 设置操作类型为更新（U），并记录操作时间和用户
            pmPlateThickAddvBtTra.setOperationType("U");
            pmPlateThickAddvBtTra.setOperationTime(now);
            pmPlateThickAddvBtTra.setOperationUser(username);
            insertPmMoldSpecBtTraList.add(pmPlateThickAddvBtTra);

        }
        // 更新或者新增
        pmPlateThickAddvBtRepository.batchUpdateByPrimaryKeySelective(updateList);
        pmPlateThickAddvBtRepository.batchInsertSelective(insertList);

        for (PmPlateThickAddvBt pmPlateThickAddvBt : insertList) {
            PmPlateThickAddvBtTra pmPlateThickAddvBtTra = new PmPlateThickAddvBtTra();
            BeanUtils.copy(pmPlateThickAddvBt, pmPlateThickAddvBtTra);

            // 设置操作类型为新增（I），并记录操作时间和用户
            pmPlateThickAddvBtTra.setOperationType("I");
            pmPlateThickAddvBtTra.setOperationTime(now);
            pmPlateThickAddvBtTra.setOperationUser(username);
            insertPmMoldSpecBtTraList.add(pmPlateThickAddvBtTra);

        }
        // 插入保存或者更新记录到对应履历表
        pmPlateThickAddvBtTraRepository.batchInsertSelective(insertPmMoldSpecBtTraList);
    }

    @Override
    public void checkExistDataIntervalByDb(Long tenantId, List<PmPlateThickAddvBt> pmPlateThickAddvBtList) {
        // 获取字段集合，查询数据库该范围内数据
        List<String> stCodeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getStCode).distinct().collect(Collectors.toList());
        List<String> formPlateModeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getFormPlateMode).distinct().collect(Collectors.toList());
        List<String> adTypeModeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getAdTypeMode).distinct().collect(Collectors.toList());
        List<String> rollDirectCodeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getRollDirectCode).distinct().collect(Collectors.toList());
        List<String> rollModeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getRollMode).distinct().collect(Collectors.toList());
        List<String> heatTreatModeList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getHeatTreatMode).distinct().collect(Collectors.toList());
        List<String> rollLineNoList = pmPlateThickAddvBtList.stream().map(PmPlateThickAddvBt::getRollLineNo).distinct().collect(Collectors.toList());
        List<PmPlateThickAddvBt> existPlateThickAddvBtList = pmPlateThickAddvBtRepository.selectByCondition(Condition.builder(PmPlateThickAddvBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmPlateThickAddvBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_ST_CODE, stCodeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_FORM_PLATE_MODE, formPlateModeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_AD_TYPE_MODE, adTypeModeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_ROLL_DIRECT_CODE, rollDirectCodeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_ROLL_MODE, rollModeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_HEAT_TREAT_MODE, heatTreatModeList))
                .andWhere(Sqls.custom().andIn(PmPlateThickAddvBt.FIELD_ROLL_LINE_NO, rollLineNoList))
                .build());

        // 如果数据库存在该范围内数据，则校验
        if (CollectionUtils.isNotEmpty(existPlateThickAddvBtList)) {
            // 校验钢板厚度
            Map<String, List<PmPlateThickAddvBt>> existPlateThickBtMap = existPlateThickAddvBtList.stream().collect(Collectors.groupingBy(this::getPlateThickKey));
            // 校验组合板宽度
            Map<String, List<PmPlateThickAddvBt>> existCombinePlateWidthBtMap = existPlateThickAddvBtList.stream().collect(Collectors.groupingBy(this::getCombinePlateWidthKey));
            for (PmPlateThickAddvBt plateThickAddvBt : pmPlateThickAddvBtList) {
                // 校验钢板厚度区间是否交叉
                if (existPlateThickBtMap.containsKey(getPlateThickKey(plateThickAddvBt))) {
                    List<PmPlateThickAddvBt> plateThickAddvBtList = existPlateThickBtMap.get(getPlateThickKey(plateThickAddvBt));
                    for (PmPlateThickAddvBt existPlateThickAddvBt : plateThickAddvBtList) {
                        // 如果更新则不跟自己比较
                        if (plateThickAddvBt.getPptabId() != null &&
                                plateThickAddvBt.getPptabId().equals(existPlateThickAddvBt.getPptabId())) {
                            continue;
                        }
                        boolean slabThickIntervalCheck = Utils.isIntersect(plateThickAddvBt.getPlateThickFrom(), plateThickAddvBt.getPlateThickTo(),
                                existPlateThickAddvBt.getPlateThickFrom(), existPlateThickAddvBt.getPlateThickTo());
                        if (slabThickIntervalCheck) {
                            throw new CommonException("pm.cut_place_bt_001", existPlateThickAddvBt.getPlateThickFrom(), existPlateThickAddvBt.getPlateThickTo());
                        }
                    }
                }
                // 校验组合板宽度是否交叉
                if (existCombinePlateWidthBtMap.containsKey(getCombinePlateWidthKey(plateThickAddvBt))) {
                    List<PmPlateThickAddvBt> plateThickAddvBtList = existCombinePlateWidthBtMap.get(getCombinePlateWidthKey(plateThickAddvBt));
                    for (PmPlateThickAddvBt existPlateThickAddvBt : plateThickAddvBtList) {
                        // 如果更新则不跟自己比较
                        if (plateThickAddvBt.getPptabId() != null &&
                                plateThickAddvBt.getPptabId().equals(existPlateThickAddvBt.getPptabId())) {
                            continue;
                        }
                        boolean combinePlateWidthIntervalCheck = Utils.isIntersect(plateThickAddvBt.getCombinePlateWidthFrom(),
                                plateThickAddvBt.getCombinePlateWidthTo(), existPlateThickAddvBt.getCombinePlateWidthFrom(),
                                existPlateThickAddvBt.getCombinePlateWidthTo());
                        if (combinePlateWidthIntervalCheck) {
                            throw new CommonException("pm.plate_spec_yield_bt", existPlateThickAddvBt.getCombinePlateWidthFrom(), existPlateThickAddvBt.getCombinePlateWidthTo());
                        }
                    }
                }
            }
        }
    }

    @Override
    public void checkNewAddOrUpdateDataInterval(List<PmPlateThickAddvBt> pmPlateThickAddvBtList) {
        // 校验钢板厚度
        Map<String, List<PmPlateThickAddvBt>> plateThickBtMap = pmPlateThickAddvBtList.stream().collect(Collectors.groupingBy(this::getPlateThickKey));
        for (Map.Entry<String, List<PmPlateThickAddvBt>> entry : plateThickBtMap.entrySet()) {
            List<PmPlateThickAddvBt> plateThickAddvBtList = entry.getValue();
            for (int i = 0; i < plateThickAddvBtList.size() - 1; i++) {
                for (int j = i + 1; j < plateThickAddvBtList.size(); j++) {
                    // 校验钢板厚度区间是否交叉
                    boolean slabThickIntervalCheck = Utils.isIntersect(plateThickAddvBtList.get(i).getPlateThickFrom(), plateThickAddvBtList.get(i).getPlateThickTo(),
                            plateThickAddvBtList.get(j).getPlateThickFrom(), plateThickAddvBtList.get(j).getPlateThickTo());
                    if (slabThickIntervalCheck) {
                        throw new CommonException("pm.cut_place_bt_001", plateThickAddvBtList.get(j).getPlateThickFrom(), plateThickAddvBtList.get(j).getPlateThickTo());
                    }

                }
            }
        }

        // 校验组合板宽度
        Map<String, List<PmPlateThickAddvBt>> combinePlateWidthBtMap = pmPlateThickAddvBtList.stream().collect(Collectors.groupingBy(this::getCombinePlateWidthKey));
        for (Map.Entry<String, List<PmPlateThickAddvBt>> entry : combinePlateWidthBtMap.entrySet()) {
            List<PmPlateThickAddvBt> plateThickAddvBtList = entry.getValue();
            for (int i = 0; i < plateThickAddvBtList.size() - 1; i++) {
                for (int j = i + 1; j < plateThickAddvBtList.size(); j++) {
                    // 校验组合板宽度区间是否交叉
                    boolean combinePlateWidthIntervalCheck = Utils.isIntersect(plateThickAddvBtList.get(i).getCombinePlateWidthFrom(),
                            plateThickAddvBtList.get(i).getCombinePlateWidthTo(), plateThickAddvBtList.get(j).getCombinePlateWidthFrom(),
                            plateThickAddvBtList.get(j).getCombinePlateWidthTo());
                    if (combinePlateWidthIntervalCheck) {
                        throw new CommonException("pm.plate_spec_yield_bt", plateThickAddvBtList.get(j).getCombinePlateWidthFrom(), plateThickAddvBtList.get(j).getCombinePlateWidthTo());
                    }

                }
            }
        }
    }

    @Override
    public String getPlateThickKey(PmPlateThickAddvBt pmPlateThickAddvBt) {
        return pmPlateThickAddvBt.getStCode() + "-" + pmPlateThickAddvBt.getFormPlateMode() + "-" +
                pmPlateThickAddvBt.getAdTypeMode() + "-" + pmPlateThickAddvBt.getRollDirectCode() + "-" +
                pmPlateThickAddvBt.getRollMode() + "-" + pmPlateThickAddvBt.getHeatTreatMode() + "-" +
                pmPlateThickAddvBt.getRollLineNo() + pmPlateThickAddvBt.getCombinePlateWidthFrom() + "-" +
                pmPlateThickAddvBt.getCombinePlateWidthTo();
    }

    @Override
    public String getCombinePlateWidthKey(PmPlateThickAddvBt pmPlateThickAddvBt) {
        return pmPlateThickAddvBt.getStCode() + "-" + pmPlateThickAddvBt.getFormPlateMode() + "-" +
                pmPlateThickAddvBt.getAdTypeMode() + "-" + pmPlateThickAddvBt.getRollDirectCode() + "-" +
                pmPlateThickAddvBt.getRollMode() + "-" + pmPlateThickAddvBt.getHeatTreatMode() + "-" +
                pmPlateThickAddvBt.getRollLineNo() + pmPlateThickAddvBt.getPlateThickFrom() + "-" +
                pmPlateThickAddvBt.getPlateThickTo();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteForUi(List<PmPlateThickAddvBt> pmPlateThickAddvBtList) {
        if (CollectionUtils.isNotEmpty(pmPlateThickAddvBtList)) {
            // 删除
            pmPlateThickAddvBtRepository.batchDeleteByPrimaryKey(pmPlateThickAddvBtList);

            // 获取时间和当前操作人信息
            Date now = new Date();
            String username = DetailsHelper.getUserDetails().getUsername();
            List<PmPlateThickAddvBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmPlateThickAddvBtList.size());
            for (PmPlateThickAddvBt pmPlateThickAddvBt : pmPlateThickAddvBtList) {
                PmPlateThickAddvBtTra pmPlateThickAddvBtTra = new PmPlateThickAddvBtTra();

                // 设置操作类型为删除（D），并记录操作时间和用户
                BeanUtils.copy(pmPlateThickAddvBt, pmPlateThickAddvBtTra);
                pmPlateThickAddvBtTra.setOperationType("D");
                pmPlateThickAddvBtTra.setOperationTime(now);
                pmPlateThickAddvBtTra.setOperationUser(username);
                insertPmMoldSpecBtTraList.add(pmPlateThickAddvBtTra);

            }
            // 插入删除记录到对应履历表
            pmPlateThickAddvBtTraRepository.batchInsertSelective(insertPmMoldSpecBtTraList);
        }
    }

    @Override
    public List<PmPlateThickAddvBtDTO> exportList(PmPlateThickAddvBt pmPlateThickAddvBt) {
        List<PmPlateThickAddvBt> plateThickAddvBtList = pmPlateThickAddvBtRepository.selectList(pmPlateThickAddvBt);
        // 如果集合为空，则返回
        if (CollectionUtils.isEmpty(plateThickAddvBtList)) {
            return Collections.emptyList();
        }
        // 获取组板方式值集含义
        List<LovValueDTO> formPlateModeLovList = lovAdapter.queryLovValue(Constants.LovCode.FORM_PLATE_MODE, pmPlateThickAddvBt.getTenantId());
        // 轧制模式含义
        List<LovValueDTO> rollModeList = lovAdapter.queryLovValue(Constants.LovCode.BT_ROLL_MODE, pmPlateThickAddvBt.getTenantId());
        // 轧制方向代码含义
        List<LovValueDTO> rollDirectCodeList = lovAdapter.queryLovValue(Constants.LovCode.BT_ROLL_DIRECT_CODE, pmPlateThickAddvBt.getTenantId());
        // 轧制产线号含义
        List<LovValueDTO> rollLineNoList = lovAdapter.queryLovValue(Constants.LovCode.ROLL_LINE_NO, pmPlateThickAddvBt.getTenantId());

        Map<String, String> formPlateModeLovMap = new HashMap<>(formPlateModeLovList.size());
        Map<String, String> rollModeLovMap = new HashMap<>(rollModeList.size());
        Map<String, String> rollDirectCodeLovMap = new HashMap<>(rollDirectCodeList.size());
        Map<String, String> rollLineNoLovMap = new HashMap<>(rollLineNoList.size());

        // 赋值
        if (CollectionUtils.isNotEmpty(formPlateModeLovList)) {
            formPlateModeLovMap = formPlateModeLovList.stream().collect(Collectors.toMap(LovValueDTO::getValue, LovValueDTO::getMeaning));
        }
        if (CollectionUtils.isNotEmpty(rollModeList)) {
            rollModeLovMap = rollModeList.stream().collect(Collectors.toMap(LovValueDTO::getValue, LovValueDTO::getMeaning));
        }
        if (CollectionUtils.isNotEmpty(rollDirectCodeList)) {
            rollDirectCodeLovMap = rollDirectCodeList.stream().collect(Collectors.toMap(LovValueDTO::getValue, LovValueDTO::getMeaning));
        }

        if (CollectionUtils.isNotEmpty(rollLineNoList)) {
            rollLineNoLovMap = rollLineNoList.stream().collect(Collectors.toMap(LovValueDTO::getValue, LovValueDTO::getMeaning));
        }

        List<PmPlateThickAddvBtDTO> resultList = new ArrayList<>(formPlateModeLovList.size());
        for (PmPlateThickAddvBt line : plateThickAddvBtList) {
            if (!formPlateModeLovMap.isEmpty()) {
                line.setFormPlateModeDesc(formPlateModeLovMap.getOrDefault(line.getFormPlateMode(), ""));
            }
            if (!rollModeLovMap.isEmpty()) {
                line.setRollModeDesc(rollModeLovMap.getOrDefault(line.getRollMode(), ""));
            }
            if (!rollDirectCodeLovMap.isEmpty()) {
                line.setRollDirectCodeDesc(rollDirectCodeLovMap.getOrDefault(line.getRollDirectCode(), ""));
            }

            if (!rollLineNoLovMap.isEmpty()) {
                line.setRollLineNoDesc(rollLineNoLovMap.getOrDefault(line.getRollLineNo(), ""));
            }
            PmPlateThickAddvBtDTO pmPlateThickAddvBtDTO = new PmPlateThickAddvBtDTO();
            BeanUtils.copy(line, pmPlateThickAddvBtDTO);
            resultList.add(pmPlateThickAddvBtDTO);
        }
        return resultList;
    }
}

