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

import com.alibaba.fastjson.JSON;
import com.xisc.pm.api.dto.CtPrcPredPlanTimeDTO;
import com.xisc.pm.api.dto.PmCtCollectPoolReqDTO;
import com.xisc.pm.api.dto.PmCtCollectPoolResDTO;
import com.xisc.pm.api.dto.PmOrderOverDTO;
import com.xisc.pm.api.dto.ctevent.PmSlabApplyMakeDTO;
import com.xisc.pm.app.service.PmCtCollectPoolService;
import com.xisc.pm.domain.entity.PmSlabPoolIn;
import com.xisc.pm.domain.repository.PmSlabPoolInRepository;
import com.xisc.pm.domain.vo.CdAndQtCollectPoolVO;
import com.xisc.pm.domain.vo.CtMainVO;
import com.xisc.pm.domain.vo.QdToLineupResultSteelVO;
import com.xisc.pm.infra.client.EventClient;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.constant.CtEventConstants;
import com.xisc.pm.infra.mapper.PmCtCollectPoolMapper;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.exception.CommonException;
import io.choerodon.core.oauth.DetailsHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.hzero.boot.platform.code.builder.CodeRuleBuilder;
import org.hzero.boot.platform.code.constant.CodeConstants;
import org.hzero.core.base.BaseConstants;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 组炉合同收池
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024/8/22 14:20
 */
@Service
@Slf4j
public class PmCtCollectPoolServiceImpl implements PmCtCollectPoolService {

    private PmCtCollectPoolMapper pmCtCollectPoolMapper;

    private PmSlabPoolInRepository pmSlabPoolInRepository;

    private CodeRuleBuilder codeRuleBuilder;

    private EventClient eventClient;

    private static final int TWO = 2;

    public PmCtCollectPoolServiceImpl(PmCtCollectPoolMapper pmCtCollectPoolMapper, PmSlabPoolInRepository pmSlabPoolInRepository,
                                      CodeRuleBuilder codeRuleBuilder, EventClient eventClient) {
        this.pmCtCollectPoolMapper = pmCtCollectPoolMapper;
        this.pmSlabPoolInRepository = pmSlabPoolInRepository;
        this.codeRuleBuilder = codeRuleBuilder;
        this.eventClient = eventClient;
    }

    @Override
    public List<PmCtCollectPoolResDTO> list(PmCtCollectPoolReqDTO dto, Long tenantId) {

        // 筛选查询合同号
        List<PmCtCollectPoolResDTO> collectPoolResDTOList = pmCtCollectPoolMapper.selectOrderAndBackLog(dto, tenantId);
        if (CollectionUtils.isEmpty(collectPoolResDTOList)) {
            return Collections.emptyList();
        }
        // b)	若全程工序途径码（WHOLE_BACKLOG）的奇数位不包含字符‘A’，表示该合同不经过炼钢工序，则跳过该合同，不查询该合同的信息
        Set<String> orderNoSet = new HashSet<>();
        Set<String> wholeBacklogSet = new HashSet<>();
        collectPoolResDTOList.forEach(item -> {
            String wholeBacklog = item.getWholeBacklog();
            for (int i = 0; i < wholeBacklog.length(); i += TWO) {
                char currentChar = wholeBacklog.charAt(i);
                if (currentChar == 'A') {
                    // 如果找到 'A'，则不跳过该合同
                    orderNoSet.add(item.getOrderNo());
                    wholeBacklogSet.add(wholeBacklog);
                }
            }
        });
        if (CollectionUtils.isEmpty(orderNoSet)) {
            return Collections.emptyList();
        }

        // 将合同号（ORDER_NO）、全程工序代码（WHOLE_BACKLOG_CODE）=13作为入参
        List<CtMainVO> ctMainVOList = pmCtCollectPoolMapper.selectOverDevoByOrderNo(new ArrayList<>(orderNoSet), tenantId);
        Map<String, CtMainVO> ctMainVOMap = ctMainVOList.stream().collect(Collectors.toMap(CtMainVO::getOrderNo, Function.identity()));

        // 4.	将合同号（ORDER_NO）、计划日期作为入参，调用合同跟踪模块“组炉合同收池”接口（合同跟踪详细表CT_DET），
        // 获取全程工序代码（WHOLE_BACKLOG_CODE）=14（表示原料申请），且计划完成交货期（PLAN_DUEDATE）位于计划日期区间内的信息，具体获取如下字段：
        List<CdAndQtCollectPoolVO> poolVOList = pmCtCollectPoolMapper.selectList(dto, tenantId, new ArrayList<>(orderNoSet));
        if (CollectionUtils.isEmpty(poolVOList)) {
            return Collections.emptyList();
        }

        // c)	计算可收池量、最小订货重量、最大订货重量
        for (int i = 0; i < poolVOList.size(); i++) {
            // 订货重量 * 交货重量负公差/100.0
            BigDecimal orderMinusWt = BigDecimal.ZERO;
            if (poolVOList.get(i).getOrderWt() != null && poolVOList.get(i).getDelivyWtTolMinus() != null) {
                orderMinusWt = poolVOList.get(i).getOrderWt().multiply(poolVOList.get(i).getDelivyWtTolMinus())
                        .divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP);
            }
            // 订货重量 * 交货重量正公差/100.0
            BigDecimal orderPlusWt = BigDecimal.ZERO;
            if (poolVOList.get(i).getOrderWt() != null && poolVOList.get(i).getDelivyWtTolPlus() != null) {
                orderPlusWt = poolVOList.get(i).getOrderWt().multiply(poolVOList.get(i).getDelivyWtTolPlus())
                        .divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP);
            }
            // 1.	可收池量
//            BigDecimal canChooseWt = (Utils.getBigDecimalValue(poolVOList.get(i).getOrdRemWgt()))
//                    .add(orderMinusWt).subtract(Utils.getBigDecimalValue(poolVOList.get(i).getPlanWgt()));
            // 2.	最小订货重量
            BigDecimal orderWtMin = Utils.getBigDecimalValue(poolVOList.get(i).getOrderWt()).subtract(orderPlusWt);
            // 3.	最大订货重量
            BigDecimal orderWtMax = Utils.getBigDecimalValue(poolVOList.get(i).getOrderWt()).add(orderMinusWt);
//            poolVOList.get(i).setCanChooseWt(canChooseWt);
            poolVOList.get(i).setOrderWtMin(orderWtMin);
            poolVOList.get(i).setOrderWtMax(orderWtMax);

        }
        // 转map,方便取值
        List<String> orderNoList = new ArrayList<>(poolVOList.size());
        Map<String, CdAndQtCollectPoolVO> collectPoolMap = new HashMap<>(poolVOList.size());
        for (CdAndQtCollectPoolVO cdAndQtCollectPoolVO : poolVOList) {
            if (cdAndQtCollectPoolVO.getPlanEndDate() == null) {
                orderNoList.add(cdAndQtCollectPoolVO.getOrderNo());
            }
            collectPoolMap.put(cdAndQtCollectPoolVO.getOrderNo(), cdAndQtCollectPoolVO);
        }

        // 将合同号（ORDER_NO）、全程工序途径码（WHOLE_BACKLOG）、产线号（MSC_LINE_NO）以及前端传入的板坯去向、板坯厚度、板坯宽度作为入参，调用质量模块“组炉合同收池”接口
        List<PmCtCollectPoolResDTO> resultList = pmCtCollectPoolMapper.selectListByQd(new ArrayList<>(orderNoSet),
                new ArrayList<>(wholeBacklogSet), dto, tenantId);

        // 获取到日期为空的，调用合同接口
        Map<String, CtPrcPredPlanTimeDTO>  planTimeDTOMap = new HashMap<>(resultList.size());
        if (CollectionUtils.isNotEmpty(orderNoList)) {
            List<CtPrcPredPlanTimeDTO> ctPrcPredPlanTimeDTOList = eventClient.planDeliveryCompletedApi(tenantId, orderNoList);
            for (CtPrcPredPlanTimeDTO predPlanTimeDTO : ctPrcPredPlanTimeDTOList) {
                if ("14".equals(predPlanTimeDTO.getWholeBacklogCode())) {
                    planTimeDTOMap.put(predPlanTimeDTO.getOrderNo(), predPlanTimeDTO);
                }
            }
        }


        // 连铸机类型
        String ccType = Constants.OrderTypeCode.QBP.equals(dto.getOrderTypeCode()) ? "4" : "2";
        // 厂别
        String mainBacklogCode = dto.getMscLineNo().startsWith("00") ? "A" : "C";
        Date now = new Date();
        // 组装数据
        for (PmCtCollectPoolResDTO pmCtCollectPoolResDTO : resultList) {
            if (collectPoolMap.containsKey(pmCtCollectPoolResDTO.getOrderNo())) {
                CdAndQtCollectPoolVO collectPoolVO = collectPoolMap.get(pmCtCollectPoolResDTO.getOrderNo());
                pmCtCollectPoolResDTO.setOrderWtMin(collectPoolVO.getOrderWtMin());
                pmCtCollectPoolResDTO.setOrderWtMax(collectPoolVO.getOrderWtMax());
                pmCtCollectPoolResDTO.setOrderWt(collectPoolVO.getOrderWt());
                pmCtCollectPoolResDTO.setOrderWtMax(collectPoolVO.getOrderWtMax());
                pmCtCollectPoolResDTO.setOrderWtMin(collectPoolVO.getOrderWtMin());
                // 获取日期
                CtPrcPredPlanTimeDTO predPlanTimeDTO = planTimeDTOMap.getOrDefault(pmCtCollectPoolResDTO.getOrderNo(), new CtPrcPredPlanTimeDTO());
                Date planEndDate =  collectPoolVO.getPlanEndDate() != null ? collectPoolVO.getPlanEndDate() :
                        (predPlanTimeDTO.getPlanEndDate() != null ? predPlanTimeDTO.getPlanEndDate() : now);
                Date latestEndDate = collectPoolVO.getLatestEndDate() != null ? collectPoolVO.getLatestEndDate() :
                        (predPlanTimeDTO.getLatestEndDate() != null ? predPlanTimeDTO.getLatestEndDate() : now);
                pmCtCollectPoolResDTO.setPlanEndDate(planEndDate);
                pmCtCollectPoolResDTO.setLatestEndDate(latestEndDate);
                pmCtCollectPoolResDTO.setDelivyDate(collectPoolVO.getDelivyDate());
                pmCtCollectPoolResDTO.setOrderTypeCode(collectPoolVO.getOrderTypeCode());
                pmCtCollectPoolResDTO.setSgSign(collectPoolVO.getSgSign());
                pmCtCollectPoolResDTO.setSgCode(collectPoolVO.getSgCode());
                pmCtCollectPoolResDTO.setMainBacklogCode(mainBacklogCode);
                pmCtCollectPoolResDTO.setWholeBacklogCode(collectPoolVO.getWholeBacklogCode());
                pmCtCollectPoolResDTO.setCcType(ccType);
                pmCtCollectPoolResDTO.setUrgOrderFlag(collectPoolVO.getUrgOrderFlag());
                pmCtCollectPoolResDTO.setDelayFlag(collectPoolVO.getDelayFlag());
                pmCtCollectPoolResDTO.setOrdRemNum(collectPoolVO.getOrdRemNum());

                CtMainVO ctMainVO = ctMainVOMap.get(pmCtCollectPoolResDTO.getOrderNo());
                if (Objects.isNull(ctMainVO)) {
                    continue;
                }
                pmCtCollectPoolResDTO.setOverDevoNumTotal(ctMainVO.getOverDevoNumTotal());
                pmCtCollectPoolResDTO.setOverDevoWgtTotal(ctMainVO.getOverDevoWgtTotal());
                pmCtCollectPoolResDTO.setCanChooseNum(ctMainVO.getStockNum() != null ? Long.valueOf(ctMainVO.getStockNum().longValue()) : 0L);
                pmCtCollectPoolResDTO.setCanChooseWt(ctMainVO.getStockWgt());

                // 计算可收池块数
//                if (pmCtCollectPoolResDTO.getNomSlabWt() != null && pmCtCollectPoolResDTO.getNomSlabWt().compareTo(BigDecimal.ZERO) != 0) {
//                    BigDecimal divide = pmCtCollectPoolResDTO.getCanChooseWt().
//                            divide(pmCtCollectPoolResDTO.getNomSlabWt(), 0, BigDecimal.ROUND_DOWN);
//                    pmCtCollectPoolResDTO.setCanChooseNum(divide.longValue());
//                } else {
//                    log.info("合同号为{}的额定板坯重量的值为0无法计算可收池块数", pmCtCollectPoolResDTO.getOrderNo());
//                }
            }
        }
        // 过滤掉无法计算可收池量的数据
        List<PmCtCollectPoolResDTO> filterResultList = resultList.stream().filter(item -> item.getCanChooseNum() != null)
                .collect(Collectors.toList());
        return filterResultList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void collectList(Long tenantId, List<PmCtCollectPoolResDTO> poolResList) {
        // 校验
        checkFieldNotEmpty(poolResList);

        // 校验线膨胀系数不可为空
        List<String> orderNoList = new ArrayList<>(poolResList.size());
        List<String> mscLineNoList = new ArrayList<>(poolResList.size());
        for (PmCtCollectPoolResDTO dto : poolResList) {
            orderNoList.add(dto.getOrderNo());
            mscLineNoList.add(dto.getMscLineNo());
        }
       List<QdToLineupResultSteelVO> resultSteelVOList = pmCtCollectPoolMapper.selectQdToLineupResultSteelList(orderNoList, mscLineNoList, tenantId);
        Map<String, QdToLineupResultSteelVO>  resultSteelMap = new HashMap<>(resultSteelVOList.size());
        if (CollectionUtils.isNotEmpty(resultSteelVOList)) {
            resultSteelMap = resultSteelVOList.stream()
                    .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()), Function.identity()));
        }
        for (PmCtCollectPoolResDTO dto : poolResList) {
            QdToLineupResultSteelVO resultSteelVO = resultSteelMap.get(Strings.concat(dto.getOrderNo(), dto.getMscLineNo()));
            if (Objects.isNull(resultSteelVO)) {
                throw new CommonException("pm.slab_pool_in_009", dto.getOrderNo(), dto.getMscLineNo());
            }
            if (resultSteelVO.getExpandQuot() == null) {
                throw new CommonException("pm.slab_pool_in_010", dto.getOrderNo(), dto.getMscLineNo());
            }

        }

        // 获取当前用户id
        Long userId = DetailsHelper.getUserDetails().getUserId();
        // 插入收池表集合
        List<PmSlabPoolIn> poolInList = new ArrayList<>(poolResList.size());

        // 获取虚拟板坯号数量
        long total = poolResList.stream().mapToLong(PmCtCollectPoolResDTO::getCanChooseNum).sum();

        // 批量生成的虚拟板坯号
        List<String> virtualNoList = codeRuleBuilder.batchGenerateCode((int) total, tenantId, Constants.CodeRule.WG_VIRTUAL_SLAB_NO,
                CodeConstants.CodeRuleLevelCode.GLOBAL, Constants.CodeRule.GLOBAL_LEVEL_VALUE, null);
        // 遍历组装数据
        int i = 0;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(BaseConstants.Pattern.NONE_DATE);
        List<PmSlabApplyMakeDTO> resList = new ArrayList<>();
        String eventCode = "";
        for (PmCtCollectPoolResDTO dto : poolResList) {
            for (long j = 0; j < dto.getCanChooseNum(); j++) {
                PmSlabPoolIn pmSlabPoolIn = new PmSlabPoolIn();
                pmSlabPoolIn.setVirtualSlabNo(virtualNoList.get(i++));
                pmSlabPoolIn.setMainBacklogCode(dto.getMainBacklogCode());
                pmSlabPoolIn.setWholeBacklogCode(dto.getWholeBacklogCode());
                pmSlabPoolIn.setOrderNo(dto.getOrderNo());
                pmSlabPoolIn.setStNo(dto.getStNo());
                pmSlabPoolIn.setSteelPlanDate(dto.getPlanEndDate());
                pmSlabPoolIn.setSlabDest(dto.getSlabDest());
                pmSlabPoolIn.setWholeBacklog(dto.getWholeBacklog());
                pmSlabPoolIn.setCcType(dto.getCcType());
                pmSlabPoolIn.setNomSlabThick(dto.getNomSlabThick());
                pmSlabPoolIn.setNomSlabLen(dto.getNomSlabLen());
                pmSlabPoolIn.setSlabMaxNomLen(dto.getSlabMaxNomLen());
                pmSlabPoolIn.setSlabMinNomLen(dto.getSlabMinNomLen());
                pmSlabPoolIn.setNomSlabWidth(dto.getNomSlabWidth());
                pmSlabPoolIn.setNomSlabWt(dto.getNomSlabWt());
                pmSlabPoolIn.setSlabMaxNomWt(dto.getSlabMaxNomWt());
                pmSlabPoolIn.setSlabMinNomWt(dto.getSlabMinNomWt());
                pmSlabPoolIn.setSlabPlaceCode(dto.getSlabPlaceCode());
                pmSlabPoolIn.setUrgOrderFlag(dto.getUrgOrderFlag());
                if (StringUtils.isNotEmpty(dto.getDelivyDate())) {
                    LocalDate localDate = LocalDate.parse(dto.getDelivyDate(), formatter);
                    // 设置时间为 23:59:59
                    LocalDateTime localDateTime = localDate.atTime(23, 59, 59);
                    // 转换为 java.util.Date
                    Timestamp timestamp = Timestamp.valueOf(localDateTime.format(DateTimeFormatter.ofPattern(BaseConstants.Pattern.DATETIME)));
                    Date date = new Date(timestamp.getTime());
                    pmSlabPoolIn.setDelivyDate(date);
                }
                pmSlabPoolIn.setOrderTypeCode(dto.getOrderTypeCode());
                pmSlabPoolIn.setSgSign(dto.getSgSign());
                pmSlabPoolIn.setSgCode(dto.getSgCode());
                pmSlabPoolIn.setOrderDelayFlag(dto.getDelayFlag());
                pmSlabPoolIn.setNomHotSendFlag("C");
                pmSlabPoolIn.setOrderHotChargeFlag("0");
                pmSlabPoolIn.setPressUseCode(null);
                pmSlabPoolIn.setUserId(userId.toString());
                pmSlabPoolIn.setEstaStatus("0");
                pmSlabPoolIn.setMscLineNo(dto.getMscLineNo());
                pmSlabPoolIn.setRfPath(dto.getRefineRouteCode());
                pmSlabPoolIn.setTenantId(tenantId);
                poolInList.add(pmSlabPoolIn);

                // 虚拟板坯号信息
                PmSlabApplyMakeDTO applyMakeDTO = new PmSlabApplyMakeDTO();
                applyMakeDTO.setMatNo(pmSlabPoolIn.getVirtualSlabNo());
                if (Constants.OrderTypeCode.QBP.equals(dto.getOrderTypeCode())) {
                    applyMakeDTO.setPpFlag(3);
                    eventCode = CtEventConstants.EVENT_PM_TAKE_OUT_SLAB_APPLY_MAKE;
                } else if (Constants.OrderTypeCode.YZA.equals(dto.getOrderTypeCode())) {
                    applyMakeDTO.setPpFlag(4);
                    eventCode = CtEventConstants.EVENT_PM_PREPARATION_SLAB_APPLY_MAKE;
                } else {
                    throw new CommonException("pm.slab_pool_in_005",pmSlabPoolIn.getVirtualSlabNo(), dto.getOrderTypeCode());
                }
                applyMakeDTO.setOrderNo(pmSlabPoolIn.getOrderNo());
                applyMakeDTO.setPdMatStatus(null);
                applyMakeDTO.setOrdFlag("1");
                applyMakeDTO.setProcCd("14A");
                applyMakeDTO.setWholeBacklogCode("14");
                applyMakeDTO.setThk(pmSlabPoolIn.getNomSlabThick());
                applyMakeDTO.setWid(pmSlabPoolIn.getNomSlabWidth());
                applyMakeDTO.setLen(pmSlabPoolIn.getNomSlabLen());
                applyMakeDTO.setWgt(pmSlabPoolIn.getNomSlabWt());
                resList.add(applyMakeDTO);
            }
        }
        // 插入收池表
        pmSlabPoolInRepository.batchInsertSelective(poolInList);

        // 将以下字段作为入参，调用合同跟踪“外卖坯/备坯合同收池事件”接口，向合同跟踪抛帐：
        log.info("<=====调用外卖坯/备坯合同收池事件，入参为{}=====>", JSON.toJSONString(resList));
        eventClient.sendEventWithOutResponse(tenantId, eventCode, resList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void overOrderList(Long tenantId, List<PmCtCollectPoolResDTO> dtoList) {

        List<PmOrderOverDTO> resList = new ArrayList<>();
        for (PmCtCollectPoolResDTO dto : dtoList) {
            PmOrderOverDTO pmOrderOverDTO = new PmOrderOverDTO();
            pmOrderOverDTO.setOrderNo(dto.getOrderNo());
            pmOrderOverDTO.setContractNum(dto.getOrderNo().substring(0, 8));
            pmOrderOverDTO.setNum(dto.getOverDevoNum());
            pmOrderOverDTO.setWgt(dto.getNomSlabWt().multiply(dto.getOverDevoNum()));
            pmOrderOverDTO.setOverFlag(dto.getOverDevoFlag());
            resList.add(pmOrderOverDTO);
        }
        log.info("<=====调用外卖坯/备坯合同超投事件，入参为{}=====>", JSON.toJSONString(resList));
        eventClient.sendEventWithOutResponse(tenantId, CtEventConstants.PM_OUT_SLAB_CONTRACT_BOARD_OVER, resList);
    }

    private void checkFieldNotEmpty(List<PmCtCollectPoolResDTO> poolResList) {
        Long one = 0L;
        for (PmCtCollectPoolResDTO dto : poolResList) {
            if (dto.getNomSlabThick() == null) {
                throw new CommonException("pm.cd_rule_021", "订货厚度");
            }
            if (dto.getThickTolMin() == null) {
                throw new CommonException("pm.cd_rule_021", "厚度公差下限");
            }
            if (dto.getThickTolMax() == null) {
                throw new CommonException("pm.cd_rule_021", "厚度公差上限");
            }
            if (dto.getWidthMax() == null) {
                throw new CommonException("pm.cd_rule_021", "宽度上限");
            }
            if (dto.getWidthTolMax() == null) {
                throw new CommonException("pm.cd_rule_021", "宽度公差上限");
            }
            if (dto.getWidthMin() == null) {
                throw new CommonException("pm.cd_rule_021", "宽度下限");
            }
            if (dto.getWidthTolMin() == null) {
                throw new CommonException("pm.cd_rule_021", "宽度公差下限");
            }
            if (dto.getOrderMinLen() == null) {
                throw new CommonException("pm.cd_rule_021", "订货最小长度");
            }
            if (dto.getLenTolMin() == null) {
                throw new CommonException("pm.cd_rule_021", "长度公差下限");
            }
            if (dto.getOrderMaxLen() == null) {
                throw new CommonException("pm.cd_rule_021", "订货最大长度");
            }
            if (dto.getLenTolMax() == null) {
                throw new CommonException("pm.cd_rule_021", "长度公差上限");
            }
            if (dto.getCanChooseNum() == null || one.equals(dto.getCanChooseNum())) {
                throw new CommonException("pm.slab_pool_in_008", dto.getOrderNo());
            }
        }
    }
}

