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

import com.xisc.pm.api.dto.export.PmMidSlabAddvBtDTO;
import com.xisc.pm.app.service.PmMidSlabAddvBtService;
import com.xisc.pm.domain.entity.PmMidSlabAddvBt;
import com.xisc.pm.domain.entity.PmMidSlabAddvBtTra;
import com.xisc.pm.domain.repository.PmMidSlabAddvBtRepository;
import com.xisc.pm.domain.repository.PmMidSlabAddvBtTraRepository;
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;

/**
 * 低碳钢坯加余量基准表(PmMidSlabAddvBt)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-09-18 18:31:21
 */
@Service
public class PmMidSlabAddvBtServiceImpl implements PmMidSlabAddvBtService {

    private PmMidSlabAddvBtRepository pmMidSlabAddvBtRepository;

    private PmMidSlabAddvBtTraRepository pmMidSlabAddvBtTraRepository;

    private LovAdapter lovAdapter;

    public PmMidSlabAddvBtServiceImpl(PmMidSlabAddvBtRepository pmMidSlabAddvBtRepository, PmMidSlabAddvBtTraRepository
             pmMidSlabAddvBtTraRepository, LovAdapter lovAdapter) {
        this.pmMidSlabAddvBtRepository = pmMidSlabAddvBtRepository;
        this.pmMidSlabAddvBtTraRepository = pmMidSlabAddvBtTraRepository;
        this.lovAdapter = lovAdapter;
    }

    @Override
    public Page<PmMidSlabAddvBt> selectList(PageRequest pageRequest, PmMidSlabAddvBt pmMidSlabAddvBt) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmMidSlabAddvBtRepository.selectList(pmMidSlabAddvBt));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveData(Long tenantId, List<PmMidSlabAddvBt> pmMidSlabAddvBtList) {
        if (CollectionUtils.isEmpty(pmMidSlabAddvBtList)) {
            return;
        }
        // a)	单条记录中，“钢板厚度起”必须小于“钢板厚度止”；
        pmMidSlabAddvBtList.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 = pmMidSlabAddvBtList.stream().collect(Collectors.groupingBy(this::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) {
                        throw new CommonException("pm.cut_place_bt_004", slabAddvBtList.get(j).getPlateThickFrom(),
                                slabAddvBtList.get(j).getPlateThickTo());
                    }
                }
            }
        }

        // 与数据库记录校验区间是否交叉
        List<String> sgSignList = pmMidSlabAddvBtList.stream().map(PmMidSlabAddvBt::getSgSign).distinct().collect(Collectors.toList());
        List<String> rollLineNoList = pmMidSlabAddvBtList.stream().map(PmMidSlabAddvBt::getRollLineNo).distinct().collect(Collectors.toList());
        List<String> stNoList = pmMidSlabAddvBtList.stream().map(PmMidSlabAddvBt::getStNo).distinct().collect(Collectors.toList());
        List<Long> idList = pmMidSlabAddvBtList.stream().filter(item -> item.getPmsabId() != null).map(PmMidSlabAddvBt::getPmsabId).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))
                .andWhere(Sqls.custom().andNotIn(PmMidSlabAddvBt.FIELD_PMSAB_ID, idList, true))
                .build());
        if (CollectionUtils.isNotEmpty(existPmMidSlabAddvBtList)) {
            Map<String, List<PmMidSlabAddvBt>> existPlateThickKeyMap = existPmMidSlabAddvBtList.stream().collect(Collectors.groupingBy(this::getPlateFromKey));
            for (PmMidSlabAddvBt pmMidSlabAddvBt : pmMidSlabAddvBtList) {
                // 如果数据库数据存在该条记录，则判断区间是否交叉
                if (existPlateThickKeyMap.containsKey(getPlateFromKey(pmMidSlabAddvBt))) {
                    List<PmMidSlabAddvBt> midSlabAddvBtList = existPlateThickKeyMap.get(getPlateFromKey(pmMidSlabAddvBt));
                    for (PmMidSlabAddvBt slabAddvBt : midSlabAddvBtList) {
                        // 检查钢板厚度区间是否交叉
                        boolean slabThickIntervalCheck = Utils.isIntersect(pmMidSlabAddvBt.getPlateThickFrom(),
                                pmMidSlabAddvBt.getPlateThickTo(), slabAddvBt.getPlateThickFrom(),
                                slabAddvBt.getPlateThickTo());
                        if (slabThickIntervalCheck) {
                            throw new CommonException("pm.cut_place_bt_001", slabAddvBt.getPlateThickFrom(), slabAddvBt.getPlateThickTo());
                        }
                    }
                }
            }
        }

        // 获取当前时间和用户名
        Date now = new Date();
        String username = DetailsHelper.getUserDetails().getUsername();
        List<PmMidSlabAddvBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmMidSlabAddvBtList.size());

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

        // 记录更新操作的历史记录
        for (PmMidSlabAddvBt pmMidSlabAddvBt : updateList) {
            PmMidSlabAddvBtTra pmMidSlabAddvBtTra = new PmMidSlabAddvBtTra();
            BeanUtils.copy(pmMidSlabAddvBt, pmMidSlabAddvBtTra);

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

        }
        // 先更新后插入
        pmMidSlabAddvBtRepository.batchUpdateByPrimaryKey(updateList);
        pmMidSlabAddvBtRepository.batchInsertSelective(insertList);

        // 记录插入操作的历史记录
        for (PmMidSlabAddvBt pmMidSlabAddvBt : insertList) {
            PmMidSlabAddvBtTra pmMidSlabAddvBtTra = new PmMidSlabAddvBtTra();
            BeanUtils.copy(pmMidSlabAddvBt, pmMidSlabAddvBtTra);

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

        }
        // 执行批量插入操作
        pmMidSlabAddvBtTraRepository.batchInsertSelective(insertPmMoldSpecBtTraList);

    }

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

            // 获取时间和当前操作人信息
            Date now = new Date();
            String username = DetailsHelper.getUserDetails().getUsername();
            List<PmMidSlabAddvBtTra> insertPmMoldSpecBtTraList = new ArrayList<>(pmMidSlabAddvBtList.size());
            for (PmMidSlabAddvBt pmMidSlabAddvBt : pmMidSlabAddvBtList) {
                PmMidSlabAddvBtTra pmMidSlabAddvBtTra = new PmMidSlabAddvBtTra();

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

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

    @Override
    public List<PmMidSlabAddvBtDTO> exportList(Long tenantId, PmMidSlabAddvBt pmMidSlabAddvBt) {
        List<PmMidSlabAddvBt> midSlabAddvBtList = pmMidSlabAddvBtRepository.selectList(pmMidSlabAddvBt);
        // 如果集合为空，则返回
        if (CollectionUtils.isEmpty(midSlabAddvBtList)) {
            return Collections.EMPTY_LIST;
        }
        List<PmMidSlabAddvBtDTO> resultList = new ArrayList<>();
        // 获取轧制产线值集含义
        List<LovValueDTO> rollLineNoList = lovAdapter.queryLovValue(Constants.LovCode.ROLL_LINE_NO, tenantId);
        Map<String, String> rollLineNoLovMap = new HashMap<>(rollLineNoList.size());

        // 赋值
        if (CollectionUtils.isNotEmpty(rollLineNoList)) {
            rollLineNoLovMap = rollLineNoList.stream().collect(Collectors.toMap(LovValueDTO::getValue, LovValueDTO::getMeaning));
        }
        for (PmMidSlabAddvBt line : midSlabAddvBtList) {
            PmMidSlabAddvBtDTO dto = new PmMidSlabAddvBtDTO();
            BeanUtils.copy(line, dto);
            dto.setRollLineNoDesc(rollLineNoLovMap.getOrDefault(line.getRollLineNo(), line.getRollLineNo()));

            resultList.add(dto);
        }
        return resultList;
    }

    public String getPlateFromKey(PmMidSlabAddvBt pmMidSlabAddvBt) {
        return pmMidSlabAddvBt.getRollLineNo() + pmMidSlabAddvBt.getStNo() + pmMidSlabAddvBt.getSgSign();
    }
}

