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


import com.xisc.pm.app.service.PmSlabScrapLenBtService;
import com.xisc.pm.domain.entity.PmMinThickTolBt;
import com.xisc.pm.domain.entity.PmSlabScrapLenBt;
import com.xisc.pm.domain.entity.PmSlabScrapLenBtTra;
import com.xisc.pm.domain.repository.PmSlabScrapLenBtRepository;
import com.xisc.pm.domain.repository.PmSlabScrapLenBtTraRepository;
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;

/**
 * 余坯组板采用判定基准表(PmSlabScrapLenBt)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-07-23 14:28:34
 */
@Service
public class PmSlabScrapLenBtServiceImpl implements PmSlabScrapLenBtService {

    private PmSlabScrapLenBtRepository pmSlabScrapLenBtRepository;

    private PmSlabScrapLenBtTraRepository pmSlabScrapLenBtTraRepository;

    public PmSlabScrapLenBtServiceImpl(PmSlabScrapLenBtRepository pmSlabScrapLenBtRepository, PmSlabScrapLenBtTraRepository pmSlabScrapLenBtTraRepository) {
        this.pmSlabScrapLenBtRepository = pmSlabScrapLenBtRepository;
        this.pmSlabScrapLenBtTraRepository = pmSlabScrapLenBtTraRepository;
    }

    @Override
    public Page<PmSlabScrapLenBt> selectList(PageRequest pageRequest, PmSlabScrapLenBt pmSlabScrapLenBt) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmSlabScrapLenBtRepository.selectList(pmSlabScrapLenBt));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveData(Long tenantId, List<PmSlabScrapLenBt> pmSlabScrapLenBtList) {
        // 检查列表是否为空，如果为空则直接返回
        if (CollectionUtils.isEmpty(pmSlabScrapLenBtList)) {
            return;
        }

        // 板坯厚度起止区间、板坯宽度起止区间、板坯长度最小值/最大值、轧制产线号。更新/插入一条新纪录时，在非区间索引相同的情况下
        // ，各区间至少有一项不存在交集，否则更新/插入失败。
        // 新增记录之间校验区间是否交叉
        // 校验板坯厚度
        Map<String, List<PmSlabScrapLenBt>> slabThickBtMap = pmSlabScrapLenBtList.stream().collect(Collectors.groupingBy(this::getSlabKey));
        for (Map.Entry<String, List<PmSlabScrapLenBt>> entry : slabThickBtMap.entrySet()) {
            List<PmSlabScrapLenBt> scrapLenBtList = entry.getValue();
            for (int i = 0; i < scrapLenBtList.size() - 1; i++) {
                for (int j = i + 1; j < scrapLenBtList.size(); j++) {
                    // 校验板坯厚度区间是否交叉
                    boolean slabThickIntervalCheck = Utils.isIntersect(scrapLenBtList.get(i).getSlabThickFrom(), scrapLenBtList.get(i).getSlabThickTo(),
                            scrapLenBtList.get(j).getSlabThickFrom(), scrapLenBtList.get(j).getSlabThickTo());
                    if (!slabThickIntervalCheck) {
                        continue;
                    }

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

                    // 校验板坯长度最小值/最大值
                    boolean slabLenIntervalCheck = Utils.isIntersect(scrapLenBtList.get(i).getSlabMinLen(), scrapLenBtList.get(i).getSlabMaxLen(),
                            scrapLenBtList.get(j).getSlabMinLen(), scrapLenBtList.get(j).getSlabMaxLen());
                    if (!slabLenIntervalCheck) {
                        continue;
                    }

                    // 三个区间都存在交集，抛出异常
                    throw new CommonException("pm.pd_tmp_yield_bt_001",
                            scrapLenBtList.get(j).getSlabThickFrom(), scrapLenBtList.get(j).getSlabThickTo(),
                            scrapLenBtList.get(j).getSlabWidthFrom(), scrapLenBtList.get(j).getSlabWidthTo(),
                            scrapLenBtList.get(i).getSlabMinLen(), scrapLenBtList.get(i).getSlabMaxLen());

                }
            }
        }

        // 校验数据是否符合规则
        List<String> rollLineNoList = pmSlabScrapLenBtList.stream().map(PmSlabScrapLenBt::getRollLineNo).distinct().collect(Collectors.toList());
        List<Long> idList = pmSlabScrapLenBtList.stream().filter(item -> item.getPsslbId() != null).map(PmSlabScrapLenBt::getPsslbId).collect(Collectors.toList());
        List<PmSlabScrapLenBt> existSlabScrapLenBtList = pmSlabScrapLenBtRepository.selectByCondition(Condition.builder(PmSlabScrapLenBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmSlabScrapLenBt.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSlabScrapLenBt.FIELD_ROLL_LINE_NO, rollLineNoList))
                .andWhere(Sqls.custom().andNotIn(PmSlabScrapLenBt.FIELD_PSSLB_ID, idList, true))
                .build());

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

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

                        // 校验板坯长度最小值/最大值
                        boolean slabLenIntervalCheck = Utils.isIntersect(slabScrapLenBt.getSlabMinLen(), slabScrapLenBt.getSlabMaxLen(),
                                specBt.getSlabMinLen(), specBt.getSlabMaxLen());
                        if (!slabLenIntervalCheck) {
                            continue;
                        }

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

        // 获取当前时间和用户信息
        Date now = new Date();
        String username = DetailsHelper.getUserDetails().getUsername();
        // 初始化用于记录操作历史的列表
        List<PmSlabScrapLenBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmSlabScrapLenBtList.size());

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

        // 记录历史表
        for (PmSlabScrapLenBt pmSlabScrapLenBt : updateList) {
            PmSlabScrapLenBtTra pmSlabScrapLenBtTra = new PmSlabScrapLenBtTra();
            BeanUtils.copyProperties(pmSlabScrapLenBt, pmSlabScrapLenBtTra);

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

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

        for (PmSlabScrapLenBt pmSlabScrapLenBt : insertList) {
            PmSlabScrapLenBtTra pmSlabScrapLenBtTra = new PmSlabScrapLenBtTra();
            BeanUtils.copyProperties(pmSlabScrapLenBt, pmSlabScrapLenBtTra);

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

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

    private String getSlabKey(PmSlabScrapLenBt slabScrapLenBt) {
        return slabScrapLenBt.getRollLineNo();
    }

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

            // 获取时间和当前操作人信息
            Date now = new Date();
            String username = DetailsHelper.getUserDetails().getUsername();
            List<PmSlabScrapLenBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmSlabScrapLenBtList.size());
            for (PmSlabScrapLenBt pmSlabScrapLenBt : pmSlabScrapLenBtList) {
                PmSlabScrapLenBtTra pmSlabScrapLenBtTra = new PmSlabScrapLenBtTra();

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

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

