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


import com.xisc.pm.app.service.PmSlabSpecBtService;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.entity.PmSlabSpecBtTra;
import com.xisc.pm.domain.repository.PmSlabSpecBtRepository;
import com.xisc.pm.domain.repository.PmSlabSpecBtTraRepository;
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.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 连铸板坯生产规格基准表(PmSlabSpecBt)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-07-23 08:24:45
 */
@Service
public class PmSlabSpecBtServiceImpl implements PmSlabSpecBtService {

    private PmSlabSpecBtRepository pmSlabSpecBtRepository;

    private PmSlabSpecBtTraRepository pmSlabSpecBtTraRepository;

    public PmSlabSpecBtServiceImpl(PmSlabSpecBtRepository pmSlabSpecBtRepository, PmSlabSpecBtTraRepository pmSlabSpecBtTraRepository) {
        this.pmSlabSpecBtRepository = pmSlabSpecBtRepository;
        this.pmSlabSpecBtTraRepository = pmSlabSpecBtTraRepository;
    }

    @Override
    public Page<PmSlabSpecBt> selectList(PageRequest pageRequest, PmSlabSpecBt pmSlabSpecBt) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmSlabSpecBtRepository.selectList(pmSlabSpecBt));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveData(Long tenantId, List<PmSlabSpecBt> pmSlabSpecBtList) {
        // 检查列表是否为空，如果为空则直接返回
        if (CollectionUtils.isEmpty(pmSlabSpecBtList)) {
            return;
        }
        // j.k.	唯一性索引：轧制方向代码、板坯厚度起止区间、板坯宽度起止区间、连铸机类型、加热炉板坯长度最小值、加热炉板坯长度最大值,轧制产线号。更新/插入一条纪录时，
        // 在非区间索引相同的情况下，各区间至少有一项不存在交集，否则更新/插入失败。
        // 新增记录之间校验区间是否交叉
        // 校验板坯厚度
        Map<String, List<PmSlabSpecBt>> slabThickBtMap = pmSlabSpecBtList.stream().collect(Collectors.groupingBy(this::getSlabKey));
        for (Map.Entry<String, List<PmSlabSpecBt>> entry : slabThickBtMap.entrySet()) {
            List<PmSlabSpecBt> slabSpecBtList = entry.getValue();
            for (int i = 0; i < slabSpecBtList.size() - 1; i++) {
                for (int j = i + 1; j < slabSpecBtList.size(); j++) {
                    // 校验板坯厚度区间是否交叉
                    boolean slabThickIntervalCheck = Utils.isIntersect(slabSpecBtList.get(i).getSlabThickFrom(),
                            slabSpecBtList.get(i).getSlabThickTo(), slabSpecBtList.get(j).getSlabThickFrom(),
                            slabSpecBtList.get(j).getSlabThickTo());
                    if (!slabThickIntervalCheck) {
                        continue;
                    }

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

                    // 校验加热炉板坯区间是否交叉
                    boolean slabLenIntervalCheck = Utils.isIntersect(slabSpecBtList.get(i).getSlabMinLen(),
                            slabSpecBtList.get(i).getSlabMaxLen(), slabSpecBtList.get(j).getSlabMinLen(),
                            slabSpecBtList.get(j).getSlabMaxLen());
                    if (!slabLenIntervalCheck) {
                        continue;
                    }
                    // 三个区间都存在交集，抛出异常
                    throw new CommonException("pm.slab_spec_bt_001",
                            slabSpecBtList.get(j).getSlabThickFrom(), slabSpecBtList.get(j).getSlabThickTo(),
                            slabSpecBtList.get(j).getSlabWidthFrom(), slabSpecBtList.get(j).getSlabWidthTo(),
                            slabSpecBtList.get(j).getSlabMinLen(), slabSpecBtList.get(j).getSlabMaxLen());

                }
            }
        }

        // 获取字段集合，查询数据库该范围内数据
        List<String> rollDirectCodeList = pmSlabSpecBtList.stream().map(PmSlabSpecBt::getRollDirectCode).collect(Collectors.toList());
        List<String> ccTypeList = pmSlabSpecBtList.stream().map(PmSlabSpecBt::getCcType).collect(Collectors.toList());
        List<String> rollLineNoList = pmSlabSpecBtList.stream().map(PmSlabSpecBt::getRollLineNo).collect(Collectors.toList());
        List<Long> pssbIdList = pmSlabSpecBtList.stream().filter(pmSlabSpecBt -> pmSlabSpecBt.getPssbId() != null)
                .map(PmSlabSpecBt::getPssbId).collect(Collectors.toList());
        List<PmSlabSpecBt> existSlabSpecBtList = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCodeList))
                .andWhere(Sqls.custom().andIn(PmSlabSpecBt.FIELD_CC_TYPE, ccTypeList))
                .andWhere(Sqls.custom().andIn(PmSlabSpecBt.FIELD_ROLL_LINE_NO, rollLineNoList))
                .andWhere(Sqls.custom().andNotIn(PmSlabSpecBt.FIELD_PSSB_ID, pssbIdList, true))
                .build());

        // 与数据库记录校验区间是否交叉
        if (CollectionUtils.isNotEmpty(existSlabSpecBtList)) {
            // 校验区间
            Map<String, List<PmSlabSpecBt>> existSlabBtMap = existSlabSpecBtList.stream().collect(Collectors.groupingBy(this::getSlabKey));
            for (PmSlabSpecBt slabSpecBt : pmSlabSpecBtList) {
                if (existSlabBtMap.containsKey(getSlabKey(slabSpecBt))) {
                    List<PmSlabSpecBt> slabSpecBtValueList = existSlabBtMap.get(getSlabKey(slabSpecBt));
                    for (PmSlabSpecBt specBt : slabSpecBtValueList) {
                        // 校验板坯厚度区间是否交叉
                        boolean slabThickIntervalCheck = Utils.isIntersect(slabSpecBt.getSlabThickFrom()
                                , slabSpecBt.getSlabThickTo(), specBt.getSlabThickFrom(), specBt.getSlabThickTo());
                        if (!slabThickIntervalCheck) {
                            continue;
                        }

                        // 校验板坯宽度区间是否交叉
                        boolean slabWidthIntervalCheck = Utils.isIntersect(slabSpecBt.getSlabWidthFrom()
                                , slabSpecBt.getSlabWidthTo(), specBt.getSlabWidthFrom(), specBt.getSlabWidthTo());
                        if (!slabWidthIntervalCheck) {
                            continue;
                        }

                        // 校验加热炉板坯区间是否交叉
                        boolean slabLenIntervalCheck = Utils.isIntersect(slabSpecBt.getSlabMinLen(),
                                slabSpecBt.getSlabMaxLen(), specBt.getSlabMinLen(), specBt.getSlabMaxLen());
                        if (!slabLenIntervalCheck) {
                            continue;
                        }

                        // 三个区间都存在交集，抛出异常
                        throw new CommonException("pm.slab_spec_bt_002", specBt.getSlabThickFrom(), specBt.getSlabThickTo(),
                                specBt.getSlabWidthFrom(), specBt.getSlabWidthTo(),specBt.getSlabMinLen(), specBt.getSlabMaxLen());
                    }
                }
            }
        }

        // 分别筛选出待新增和待更新的
        List<PmSlabSpecBt> insertList = pmSlabSpecBtList.stream().filter(line -> line.getPssbId() == null).collect(Collectors.toList());
        List<PmSlabSpecBt> updateList = pmSlabSpecBtList.stream().filter(line -> line.getPssbId() != null).collect(Collectors.toList());

        // 获取当前时间和用户信息。
        Date now = new Date();
        String username = DetailsHelper.getUserDetails().getUsername();
        List<PmSlabSpecBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmSlabSpecBtList.size());


        // 记录历史表
        for (PmSlabSpecBt pmMoldSpecBt : updateList) {
            PmSlabSpecBtTra pmSlabSpecBtTra = new PmSlabSpecBtTra();
            BeanUtils.copyProperties(pmMoldSpecBt, pmSlabSpecBtTra);

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

        }
        // 更新或者新增
        pmSlabSpecBtRepository.batchUpdateByPrimaryKey(updateList);
        pmSlabSpecBtRepository.batchInsertSelective(insertList);

        for (PmSlabSpecBt pmMoldSpecBt : insertList) {
            PmSlabSpecBtTra pmSlabSpecBtTra = new PmSlabSpecBtTra();
            BeanUtils.copyProperties(pmMoldSpecBt, pmSlabSpecBtTra);

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

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

    private String getSlabKey(PmSlabSpecBt slabSpecBt) {
        return slabSpecBt.getRollDirectCode()  + "-" + slabSpecBt.getCcType() +"-" + slabSpecBt.getRollLineNo();
    }



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

            // 获取时间和当前操作人信息
            Date now = new Date();
            String username = DetailsHelper.getUserDetails().getUsername();
            List<PmSlabSpecBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmSlabSpecBtList.size());
            for (PmSlabSpecBt pmSlabSpecBt : pmSlabSpecBtList) {
                PmSlabSpecBtTra pmSlabSpecBtTra = new PmSlabSpecBtTra();

                // 设置操作类型为插入（D），并记录操作时间和用户
                BeanUtils.copyProperties(pmSlabSpecBt, pmSlabSpecBtTra);
                pmSlabSpecBtTra.setOperationType("D");
                pmSlabSpecBtTra.setOperationTime(now);
                pmSlabSpecBtTra.setOperationUser(username);
                insertPmMoldSpecBtTraList.add(pmSlabSpecBtTra);

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

