package com.xisc.pm.app.service.strategy.pdmattype;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xisc.pm.api.dto.PmBoardMatInfoDTO;
import com.xisc.pm.api.dto.PmCompositeSlabCalcDTO;
import com.xisc.pm.api.dto.PmProContFilterRequestDTO;
import com.xisc.pm.api.dto.PmProContFilterResposeDTO;
import com.xisc.pm.api.dto.PmProContYieldDTO;
import com.xisc.pm.api.dto.PmProContYieldRequestDTO;
import com.xisc.pm.api.dto.PmProContYieldResposeDTO;
import com.xisc.pm.api.dto.RuleParamDTO;
import com.xisc.pm.api.dto.ctevent.ProMatContBoardEndDTO;
import com.xisc.pm.app.service.PmCmdSlabService;
import com.xisc.pm.app.service.PmPdPlateService;
import com.xisc.pm.app.service.strategy.PdMatTypeStrategyFactory;
import com.xisc.pm.app.service.strategy.formplatemode.FormPlateModeStrategy;
import com.xisc.pm.domain.entity.PmContMscTech;
import com.xisc.pm.domain.entity.PmPdContSum;
import com.xisc.pm.domain.entity.PmPdPlate;
import com.xisc.pm.domain.entity.PmPlateCutLenBt;
import com.xisc.pm.domain.entity.PmProCont;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.entity.PmSmallPltPos;
import com.xisc.pm.domain.repository.PmPdPlateRepository;
import com.xisc.pm.domain.repository.PmProContRepository;
import com.xisc.pm.domain.vo.CtMainVO;
import com.xisc.pm.domain.vo.MatStatusModifyVO;
import com.xisc.pm.domain.vo.MmPlateVO;
import com.xisc.pm.infra.client.MmEventClient;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.constant.Constants.CcType;
import com.xisc.pm.infra.constant.Constants.PdStatusHp;
import com.xisc.pm.infra.constant.CtEventConstants;
import com.xisc.pm.infra.constant.PmPlateConstants;
import com.xisc.pm.infra.constant.RuleSetConstants;
import com.xisc.pm.infra.enums.PdEventType;
import com.xisc.pm.infra.enums.PdMatType;
import com.xisc.pm.infra.enums.PdProdFlag;
import com.xisc.pm.infra.enums.PdRuleSetType;
import com.xisc.pm.infra.util.BeanUtils;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.exception.CommonException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hzero.boot.platform.lov.adapter.LovAdapter;
import org.hzero.core.base.BaseConstants;
import org.hzero.core.message.Message;
import org.hzero.core.message.MessageAccessor;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * 余材钢板组板
 * 
 * @author jun.zeng
 *
 */
@Slf4j
@Component
public class PlatePdMatTypeStratrgy extends DefaultPdMatTypeStrategy<PmPdPlate> {

    @Autowired
    private PmPdPlateService pmPdPlateService;

    @Autowired
    private PmPdPlateRepository pmPdPlateRepository;

    @Autowired
    private PmCmdSlabService pmCmdSlabService;

    @Autowired
    private MmEventClient mmEventClient;

    @Autowired
    private PmProContRepository pmProContRepository;
    @Autowired
    private LovAdapter lovAdapter;

    @Override
    public void afterPropertiesSet() throws Exception {
        PdMatTypeStrategyFactory.register(PdMatType.P, this);
    }

    @Override
    public void contFilterInitParam(PmProContFilterRequestDTO pmProContFilterRequest) {
        pmProContFilterRequest.check();
        if (pmProContFilterRequest.getPlateId() == null) {
            throw new CommonException("pm.pm_pd_plate_001");
        }
        MmPlateVO mmPlate = mmPlateRepository.selectByPrimary(pmProContFilterRequest.getPlateId());
        if (mmPlate == null) {
            throw new CommonException("pm.pm_pd_plate_001");
        }
        pmProContFilterRequest.setSgSign(null);
        pmProContFilterRequest.setMmPlate(mmPlate);
        if(StringUtils.isNotBlank(mmPlate.getSlabNo())) {
            char first = mmPlate.getSlabNo().charAt(0);
            if(first == 'F' || first == 'K') {
                pmProContFilterRequest.setQueryQfh(BaseConstants.Flag.YES.toString());
            }
        }
        // 钢板未综判（综判代码为0），符合以优充次的合同也会抽出
        if (Constants.ValidFlag.ZERO.equals(mmPlate.getComplexDecideCode())) {
            pmProContFilterRequest.setStReplFlag(BaseConstants.Flag.YES.longValue());
        } else {
            pmProContFilterRequest.setStReplFlag(BaseConstants.Flag.NO.longValue());
        }
    }

    @Override
    public boolean contFilterRuleSetCheck(PmProContFilterRequestDTO pmProContFilterRequestD,
            PmProContFilterResposeDTO pmProContFilterResposeDTO, List<PmSlabSpecBt> pmSlabSpecBts,
            Map<String, CtMainVO> cmCtMainMap) {
        // 调用规则集，筛选合同
        RuleParamDTO ruleParam = initRuleParamPlate(PdRuleSetType.P06, pmProContFilterRequestD.getMmPlate(),
                pmProContFilterResposeDTO, pmProContFilterRequestD);
        ;
        // 补充规则校验
        RuleParamDTO supplementaryRuleParam = initRuleParamPlate(PdRuleSetType.P01,
                pmProContFilterRequestD.getMmPlate(), pmProContFilterResposeDTO, pmProContFilterRequestD);
        ruleParam.buildExcludeRuleNo(pmProContFilterRequestD);
        supplementaryRuleParam.buildExcludeRuleNo(pmProContFilterRequestD);
        try {
            pmPdRuleSetService.runRuleSet(ruleParam);
            if (checkAndFillExtendInfo(pmProContFilterResposeDTO, cmCtMainMap)) {
                return true;
            } else {
                return false;
            }
        } catch (CommonException e) {
            if (supplementaryRuleParam != null) {
                // 如果补充规则不为空执行补充规则集校验
                try {
                    pmPdRuleSetService.runRuleSet(supplementaryRuleParam);
                    if (checkAndFillExtendInfo(pmProContFilterResposeDTO, cmCtMainMap)) {
                        return true;
                    } else {
                        return false;
                    }
                } catch (CommonException e1) {
                    Message message = MessageAccessor.getMessage(e1.getCode(), e1.getParameters());
                    pmProContFilterResposeDTO.setUnSelectedReason(message.getDesc());
                    return false;
                }
            }
            Message message = MessageAccessor.getMessage(e.getCode(), e.getParameters());
            pmProContFilterResposeDTO.setUnSelectedReason(message.getDesc());
            return false;
        }
    }

    @Override
    public RuleParamDTO contSelectionRuleSet() {
        return new RuleParamDTO(PdRuleSetType.P03);
    }

    @Override
    public RuleParamDTO contSelectionCheckRuleSet() {
        // 无需校验轴合同与非轴合同检查规则集
        return null;
    }

    @Override
    public RuleParamDTO pdResultCheckRuleSet() {
        // 无需校验组板结果
        return new RuleParamDTO(PdRuleSetType.P05);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PmPdPlate generateResult(PmProContYieldRequestDTO pmProContYield,
            Map<String, PmProContFilterResposeDTO> filterOrderMap, PmCompositeSlabCalcDTO pmCompositeSlabCalc,
            PmProContYieldResposeDTO pmProContYieldRespose, PmContMscTech axisPmContMscTech,
            PmProContProdTtr axisPmProContProdTtr) {
        // 如果是余材板坯组板，更新组板板坯表
        return pmPdPlateService.createPmPdPlate(pmProContYield, axisPmContMscTech, axisPmProContProdTtr, filterOrderMap,
                pmProContYieldRespose, pmCompositeSlabCalc);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateCmd(PmPdPlate pmPdPlate, List<PmPdContSum> pmPdContSums, List<PmSmallPltPos> pmSmallPltPoss,
            String mscLineNo) {
        pmCmdSlabService.createPmCmdByPlate(pmPdPlate, pmPdContSums, pmSmallPltPoss, mscLineNo);
    }

    @Override
    public void yiledCalcBeforeCheck(PmProContYieldRequestDTO pmProContYield, boolean isExec) {
        pmProContYield.getPmContFilterRequest().check();
        if (isExec) {
            if (StringUtils.isBlank(pmProContYield.getVirtualSlabNo())) {
                throw new CommonException("pm.pm_pro_cont_039");
            }
            PmPdPlate record = new PmPdPlate();
            record.setPlateNo(pmProContYield.getVirtualSlabNo());
            record.setTenantId(pmProContYield.getTenantId());
            record = pmPdPlateRepository.selectOne(record);
            if (record != null) {
                throw new CommonException("pm.pm_pd_plate_002", pmProContYield.getVirtualSlabNo());
            }
        }
        if (pmProContYield.getPmContFilterRequest().getPlateId() == null) {
            throw new CommonException("pm.pm_pd_plate_001");
        }

        // 校验合同的PD_LACK_QTY+PD_OVER_DEVO_QTY+本次前台输入的超投件数大于等于当前组板的合同数量
        if(!pmProContYield.isSecondaryDesignFlag()) {
            List<String> orderNoList = Lists.newArrayList();
            Map<String , BigDecimal> currentOverDevoQtyMap = new HashMap<>();
            for (PmProContYieldDTO pmProContYieldDTO : pmProContYield.getPmProContYieldList()) {
                orderNoList.add(pmProContYieldDTO.getOrderNo());
                currentOverDevoQtyMap.put(pmProContYieldDTO.getOrderNo(), pmProContYieldDTO.getPdOverDevoQty() == null ? BigDecimal.ZERO : pmProContYieldDTO.getPdOverDevoQty());
            }
            if (orderNoList != null && !orderNoList.isEmpty()) {
                List<PmProCont> pmProConts = pmProContRepository.selectByOrderList(orderNoList, pmProContYield.getTenantId());
                for (PmProCont pmProCont : pmProConts) {
                    BigDecimal pdQty = pmProCont.getPdLackQty() == null ? BigDecimal.ZERO : pmProCont.getPdLackQty();
                    BigDecimal pdOverDevoQty = pmProCont.getPdOverDevoQty() == null ? BigDecimal.ZERO : pmProCont.getPdOverDevoQty();
                    pdQty = pdQty.add(pdOverDevoQty);
                    BigDecimal pdOverDevoQtyCurrent = currentOverDevoQtyMap.get(pmProCont.getOrderNo());
                    pdQty = pdQty.add(pdOverDevoQtyCurrent);
                    if (pmProContYield.getCompositeBoard().getOrderSpCount() != null
                            && pmProContYield.getCompositeBoard().getOrderSpCount().containsKey(pmProCont.getOrderNo())) {
                        BigDecimal orderSpCount = pmProContYield.getCompositeBoard().getOrderSpCount().get(pmProCont.getOrderNo());
                        if (orderSpCount.compareTo(pdQty) > 0) {
                            throw new CommonException("pm.pm_pro_cont_063",pmProCont.getOrderNo() 
                                    , pmProCont.getPdLackQty().toPlainString() , pdOverDevoQty.toPlainString(), pdOverDevoQtyCurrent.toPlainString());
                        }
                    }
                }
            }
        }
    }

    @Override
    public void calcRsCodeAndBroadFlag(PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr,
            PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        pmCompositeSlabCalc.setTrimWidth(BigDecimal.ZERO);
        if (pmProContYield.getCompositeBoard().getSzWidth().add(BigDecimal.ZERO)
                .compareTo(pmProContYield.getPmContFilterRequest().getMoldWidth()) <= 0) {
            pmCompositeSlabCalc.setBroadFlag(BaseConstants.Flag.NO.toString());
            pmCompositeSlabCalc.setRsCode(3);
        } else {
            pmCompositeSlabCalc.setRsCode(0);
            pmCompositeSlabCalc.setBroadFlag(BaseConstants.Flag.YES.toString());
        }
    }

    @Override
    public void calcSampleLen(PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr,
            PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        pmCompositeSlabCalc.setSampleLenHead(BigDecimal.ZERO);
        pmCompositeSlabCalc.setSampleLenTail(BigDecimal.ZERO);
        pmCompositeSlabCalc.setSampleLenMid(BigDecimal.ZERO);
        pmCompositeSlabCalc.setSampleLength(BigDecimal.ZERO);
    }

    @Override
    public PmProContYieldResposeDTO calcYield(Map<String, PmProContFilterResposeDTO> filterOrderMap,
            PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr,
            PmContMscTech axisPmContMscTech, PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        PmProContYieldResposeDTO yieldRespose = new PmProContYieldResposeDTO();
        yieldRespose.setTenantId(pmProContYield.getTenantId());
        yieldRespose.setCombinePlateWidth(pmProContYield.getCompositeBoard().getSzWidth());
        yieldRespose.setCombinePlateLen(pmProContYield.getCompositeBoard().getSzLength());
        yieldRespose.setBroadFlag(pmCompositeSlabCalc.getBroadFlag());
        yieldRespose.setRsCode(pmCompositeSlabCalc.getRsCode());
        BeanCopier copier = BeanCopier.create(PmProContFilterResposeDTO.class, PmProContProdTtr.class, false);
        BeanCopier copierContMscTech = BeanCopier.create(PmProContFilterResposeDTO.class, PmContMscTech.class, false);
        Map<String, PmProContProdTtr> pmProContProdTtrs = new HashMap<String, PmProContProdTtr>();
        Map<String, PmContMscTech> pmContMscTechs = new HashMap<String, PmContMscTech>();

        for (Entry<String, PmProContFilterResposeDTO> entry : filterOrderMap.entrySet()) {
            PmProContProdTtr pmProContProdTtr = new PmProContProdTtr();
            PmContMscTech pmContMscTech = new PmContMscTech();
            copier.copy(entry.getValue(), pmProContProdTtr, null);
            pmProContProdTtrs.put(entry.getKey(), pmProContProdTtr);
            copierContMscTech.copy(entry.getValue(), pmContMscTech, null);
            pmContMscTechs.put(entry.getKey(), pmContMscTech);
        }
        MmPlateVO mmPlateVO = mmPlateRepository.selectByPrimary(pmProContYield.getPmContFilterRequest().getPlateId());
        pmProContYield.getPmContFilterRequest().setMmPlate(mmPlateVO);
        if (mmPlateVO == null) {
            throw new CommonException("pm.pm_pd_plate_001");
        }
        
        BigDecimal headCut = BigDecimal.ZERO;
        BigDecimal tailCut = BigDecimal.ZERO;
        
        if(pmProContYield.getPmContFilterRequest().getMmPlate() != null  && "0".equals(pmProContYield.getPmContFilterRequest().getMmPlate().getFinalCutSurfaceCode())
                && "C".equals(axisPmProContProdTtr.getProdSideMark()) && "5".equals(pmProContYield.getPmContFilterRequest().getMmPlate().getStockCode())) {
            // 根据材料号mat_no（即钢板号plate_no），读取钢板主数据表（MM_PLATE）[轧钢数据]中的最终切断面代码final_cut_surface_code。
            // 若钢板未切头尾且有切边要求（即切边标记prod_side_mark取值为C、最终切断面代码final_cut_surface_code取值为0）
            // ，且库区代码为5（MM_PLATE中的STOCK_LINE）时，头部切舍量、尾部切舍量均为50。其余情况下均置为0.
            headCut = BigDecimal.valueOf(50);
            tailCut = BigDecimal.valueOf(50);
        }
        
        if(pmProContYield.isSecondaryDesignFlag()) {
            PmPdPlate record = new PmPdPlate();
            record.setPlateNo(pmProContYield.getVirtualSlabNo());
            record = pmPdPlateRepository.selectOne(record);
            if(record != null && "Z".equals(record.getAutoManualFlag()) &&
                    pmProContYield.getPmContFilterRequest().getMmPlate() != null 
                    && "1".equals(pmProContYield.getPmContFilterRequest().getMmPlate().getComplexDecideCode())) {
                headCut = BigDecimal.ZERO;
                tailCut = BigDecimal.ZERO;
            }
            yieldRespose.setTaim(mmPlateVO.getMatActThk());
            yieldRespose.setRollThickTolMax(mmPlateVO.getMatActThk().subtract(axisPmProContProdTtr.getOrderThick()));
            yieldRespose.setRollThickTolMin(mmPlateVO.getMatActThk().subtract(axisPmProContProdTtr.getOrderThick()));
            // 钢板切缝切头尾范围基准表数据
            List<PmPlateCutLenBt> plateCutLenBts = pmPlateCutLenBtRepository.selectPmPlateCutLenForPlate(pmProContYield,
                    axisPmProContProdTtr, axisPmContMscTech, pmCompositeSlabCalc.getBroadFlag(),
                    pmProContYield.getPmContFilterRequest().getMscLineNo());
            
            BigDecimal plateCutWidth = null ;
            for (PmPlateCutLenBt pmPlateCutLenBt : plateCutLenBts) {
                if(plateCutWidth == null || plateCutWidth.compareTo(pmPlateCutLenBt.getPlateCutWidth()) <= 0) {
                    plateCutWidth = pmPlateCutLenBt.getPlateCutWidth();
                }
            }
            
            // 轧制目标宽度
            if (pmCompositeSlabCalc.getRsCode() == 3) {
                yieldRespose.setWaim(pmProContYield.getPmContFilterRequest().getMoldWidth());
            } else {
                // 轧制目标宽度=组合板宽度 + (轴合同)宽度余量 + 切边量 +（取板方式_宽度方向-1） × 钢板切缝宽度
                BigDecimal waim = yieldRespose.getCombinePlateWidth();
                BigDecimal pickModeWidDir = BigDecimal.valueOf(pmProContYield.getCompositeBoard().getPickModeWidDir())
                        .subtract(BigDecimal.ONE);
                yieldRespose.setWaim(waim.add(pickModeWidDir.multiply(plateCutWidth)));
            }
            BigDecimal pickModeLenDir = BigDecimal.valueOf(pmProContYield.getCompositeBoard().getPickModeLenDir())
                    .subtract(BigDecimal.ONE);
            BigDecimal laim = yieldRespose.getCombinePlateLen().add(pmCompositeSlabCalc.getSampleLength()).add(headCut)
                    .add(tailCut).add(pickModeLenDir.multiply(plateCutWidth));
            yieldRespose.setLaim(laim);
            // (2) 基准收得率norm_yield = （订货厚度*组合板宽度*组合板长度）*（1-氧化铁皮损失率）÷（轧制目标长度*轧制目标宽度*轧制目标厚度）
            BigDecimal compositeSlabArea = axisPmProContProdTtr.getOrderThick().multiply(yieldRespose.getCombinePlateLen())
                    .multiply(yieldRespose.getCombinePlateWidth()).multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE);
            BigDecimal targetSlabArea = yieldRespose.getLaim().multiply(yieldRespose.getWaim())
                    .multiply(yieldRespose.getTaim());

            yieldRespose.setNormYield(
                    compositeSlabArea.divide(targetSlabArea, PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP));
            // 密度（克/cm^3）
            BigDecimal prodDensity = axisPmProContProdTtr.getProdDensity();
            // 厚板轧制重量roll_wt_hp = 轧制目标厚度(mm) * 轧制目标宽度(mm) * 轧制目标长度(mm) * 密度
            // 转化为吨
            yieldRespose.setRollWtHp(yieldRespose.getTaim().multiply(yieldRespose.getWaim())
                    .multiply(yieldRespose.getLaim()).multiply(prodDensity)
                    .divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));
        } else {
            // 余材钢板
            yieldRespose.setLaim(pmProContYield.getCompositeBoard().getSzLength());
            yieldRespose.setWaim(pmProContYield.getCompositeBoard().getSzWidth());
            yieldRespose.setTaim(pmProContYield.getPmContFilterRequest().getMmPlate().getMatActThk());
            yieldRespose.setRollWtHp(yieldRespose.getTaim().multiply(yieldRespose.getWaim())
                    .multiply(yieldRespose.getLaim()).multiply(PmPlateConstants.DEFAULT_PROD_DENCITY)
                    .divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));
        }
        
        yieldRespose.setHeadCut(headCut);
        yieldRespose.setTailCut(tailCut);

        calc(pmProContYield, axisPmProContProdTtr, pmCompositeSlabCalc, pmProContProdTtrs, yieldRespose);

        return yieldRespose;
    }

    /**
     * 余材组板从写计算方法
     */
    @Override
    public void calc(PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr,
            PmCompositeSlabCalcDTO pmCompositeSlabCalc, Map<String, PmProContProdTtr> pmProContProdTtrs,
            PmProContYieldResposeDTO yieldRespose) {
        FormPlateModeStrategy formPlateModeStrategy = getFormPlateModeStrategy(pmProContYield);
        // 命令收得率 ＝Σ合同单重 ÷ 材料实际重量
        BigDecimal sumPlateWt = formPlateModeStrategy.getSumPlateWt(pmProContProdTtrs, pmProContYield);
        yieldRespose.setSumPlateWt(sumPlateWt);
        yieldRespose
                .setCommandYield(sumPlateWt.divide(pmProContYield.getPmContFilterRequest().getMmPlate().getMatActWgt(),
                        PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP));
        if(yieldRespose.getCommandYield().compareTo(BigDecimal.ONE) > 0) {
            throw new CommonException("pm.pm_pd_plate_014" , sumPlateWt.toPlainString() , pmProContYield.getPmContFilterRequest().getMmPlate().getMatActWgt().toPlainString()
                    , yieldRespose.getCommandYield().toPlainString());
        }
    }

    /**
     * 补充校验与填充数据
     * 
     * @param pmProContFilterRespose
     * @param cmCtMainMap
     * @param pdMatType
     * @return
     */
    private boolean checkAndFillExtendInfo(PmProContFilterResposeDTO pmProContFilterRespose,
            Map<String, CtMainVO> cmCtMainMap) {
//        if (PmPlateConstants.ORDER_TYPE_CODE_QFH.equals(pmProContFilterRespose.getOrderTypeCode())) {
//            Message message = MessageAccessor.getMessage("pm.pm_pd_plate_013");
//            pmProContFilterRespose.setUnSelectedReason(message.getDesc());
//            return false;
//        }
        if (cmCtMainMap != null) {
            CtMainVO ctMainVO = cmCtMainMap.get(pmProContFilterRespose.getOrderNo());
            pmProContFilterRespose.setTailFlag(ctMainVO == null ? null : ctMainVO.getTailFlag());
        }
        return true;
    }

    /**
     * 规则集P06参数 当规则号RULE_NO为13，进行余材钢板厚度与合同厚度匹配 当规则号RULE_NO为10，进行实物炉次化学成分与合同匹配
     * 当规则号RULE_NO为64，进行热处理材料与合同热处理模式匹配检查 当规则号RULE_NO为7，进行内部钢种匹配检查
     * 
     * 规则集P01参数 当规则号RULE_NO为13，进行余材钢板厚度与合同厚度匹配 当规则号RULE_NO为81，进行奉送样只能A1或者S1组板检查
     * 当规则号RULE_NO为82，进行合同实重交货校验 当规则号RULE_NO为15，进行余材钢板长度与合同长度匹配检查
     * 当规则号RULE_NO为73，进行宽度方向允许组剖分板合同匹配校验 当规则号RULE_NO为60，进行余材组板牌号比对检查
     * 当规则号RULE_NO为14，进行余材钢板宽度与合同宽度匹配检查 当规则号RULE_NO为64，进行热处理材料与合同热处理模式匹配检查
     * 当规则号RULE_NO为10，进行实物炉次化学成分与合同匹配
     * 
     * @param mmPlate
     * @param pmProContFilterRespose
     * @param pmProContFilterRequest
     * @return
     */
    private RuleParamDTO initRuleParamPlate(PdRuleSetType pdRuleSetType, MmPlateVO mmPlate,
            PmProContFilterResposeDTO pmProContFilterRespose, PmProContFilterRequestDTO pmProContFilterRequest) {
        RuleParamDTO ruleParam = new RuleParamDTO(pdRuleSetType);
        Map<String, Object> bizData = new HashMap<>();
        ruleParam.setBizData(bizData);
        ruleParam.setTenantId(pmProContFilterRequest.getTenantId());
        bizData.put(RuleSetConstants.CC_TYPE, pmProContFilterRequest.getCcType());
        bizData.put(RuleSetConstants.FORM_PLATE_MODE, pmProContFilterRequest.getFormPlateMode());
        bizData.put(RuleSetConstants.MAT_DESIGN_KIND, pmProContFilterRequest.getMatDesignKind());
        bizData.put(RuleSetConstants.PM_PRO_CONT_PROD_ATTR,
                BeanUtils.copy(pmProContFilterRespose, PmProContProdTtr.class));
        bizData.put(RuleSetConstants.PM_CONT_MSC_TECH, BeanUtils.copy(pmProContFilterRespose, PmContMscTech.class));
        bizData.put(RuleSetConstants.MM_PLATE, mmPlate);
        bizData.put(RuleSetConstants.MSC_LINE_NO, pmProContFilterRespose.getMscLineNo());
        bizData.put(RuleSetConstants.ORDER_NO, pmProContFilterRespose.getOrderNo());
        bizData.put(RuleSetConstants.ST_NO, pmProContFilterRequest.getStNo());
        bizData.put(RuleSetConstants.ORDER_NO_SET, pmProContFilterRequest.getOrderNoList());
        bizData.put(RuleSetConstants.TENANT_ID, pmProContFilterRequest.getTenantId());
        if (mmPlate != null) {
            bizData.put(RuleSetConstants.PONO, mmPlate.getPono());
        }
        return ruleParam;
    }

    @Override
    public boolean needPlateCut() {
        return true;
    }

    @Override
    protected String getPlateNo(PmProContYieldRequestDTO pmProContYield) {
        // 余材组板，虚拟板坯号就是余材钢板号
        return pmProContYield.getVirtualSlabNo();
    }

    @Override
    public String getSmallPlateDivNo(String plateNo, String trimCode, int i) {
        StringBuilder plateNoBuilder = new StringBuilder(plateNo.substring(plateNo.length() - 3));
        // 找出为0的下标
        int index = Utils.findPlatNoIndexZero(plateNo);
        plateNoBuilder.setCharAt(index, PmPlateConstants.PLATE_SMALL_SPLIT_NO[i]);
        return plateNoBuilder.toString();
    }

    @Override
    public String pdProgram() {
        return Constants.PdProgram.PLATE_INFO_PD_PROGRAM;
    }

    @Override
    protected PdEventType pdDeleteEventType() {
        return PdEventType.HP15;
    }

    @Override
    protected PdEventType pdFinshedEventType() {
        return PdEventType.HP14;
    }

    @Override
    public void ctEventRec(PmPdPlate t, List<PmSmallPltPos> pmSmallPltPoss,
            Map<String, PmProContFilterResposeDTO> filterOrderMap, PmProContYieldRequestDTO pmProContYield,
            PmCompositeSlabCalcDTO pmCompositeSlabCalc, PmProContYieldResposeDTO pmProContYieldRespose) {
        List<ProMatContBoardEndDTO> boardEndEventList = new ArrayList<>();
        PmProContFilterResposeDTO axisPmProCont = filterOrderMap.get(pmProContYield.getAxisOrderNo());
        MmPlateVO mmPlateVO = pmProContYield.getPmContFilterRequest().getMmPlate();
        // 虚拟板坯维度
        boardEndEventList.add(new ProMatContBoardEndDTO(axisPmProCont.getOrderNo()).setMatNo(pmProContYield.getVirtualSlabNo())
                            .setLen(mmPlateVO.getMatActLen()).setMoMatNo(getSlabMoMatNo(pmProContYield))
                            .setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo())
                            .setPdMatStatus(PdStatusHp.PD_STATUS_HP_12).setPpFlag(PdProdFlag.VIRTUAL_SLAB.getCode())
                            .setThk(pmProContYield.getPmContFilterRequest().getMoldThick())
                            .setWid(pmProContYield.getPmContFilterRequest().getMoldWidth())
                            .setWgt(mmPlateVO.getMatActWgt())
                            .setWholeBacklogCode(getWholeBacklogCode(axisPmProCont, pmProContYield))
                            .setStNo(axisPmProCont.getStNo())
                            .setSgSign(axisPmProCont.getSgSign())
                            .setProcCd(getProcCd()));
        // 大板维度
        boardEndEventList.add(new ProMatContBoardEndDTO(axisPmProCont.getOrderNo()).setMatNo(pmProContYield.getVirtualSlabNo())
                .setLen(mmPlateVO.getMatActLen()).setMoMatNo(getSlabMoMatNo(pmProContYield))
                .setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo())
                .setPdMatStatus(PdStatusHp.PD_STATUS_HP_12).setPpFlag(PdProdFlag.VIRTUAL_COMPOSITE_SLAB.getCode())
                .setThk(mmPlateVO.getMatActThk())
                .setWid(mmPlateVO.getMatActWid())
                .setWgt(mmPlateVO.getMatActWgt())
                .setWholeBacklogCode(getWholeBacklogCode(axisPmProCont, pmProContYield))
                .setStNo(axisPmProCont.getStNo())
                .setSgSign(axisPmProCont.getSgSign())
                .setProcCd(getProcCd()));
        
        String pdMatNo = Utils.removeLastThreeChars(pmProContYield.getVirtualSlabNo());
        for (PmSmallPltPos pmSmallPltPos : pmSmallPltPoss) {
            PmProContFilterResposeDTO pmProContFilterResposeDTO = filterOrderMap.get(pmSmallPltPos.getOrderNo());
            // 小板维度
            boardEndEventList
                    .add(new ProMatContBoardEndDTO(pmSmallPltPos.getOrderNo()).setMatNo(pdMatNo + pmSmallPltPos.getSmallPlateDivNo())
                            .setLen(pmSmallPltPos.getOrderLen()).setMoMatNo(getMoMatNo(pmSmallPltPos.getPdMatNo(), pmProContYield))
                            .setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo())
                            .setPdMatStatus(PdStatusHp.PD_STATUS_HP_12).setPpFlag(getSmallPosPpFlag())
                            .setThk(pmSmallPltPos.getOrderThick()).setWid(pmSmallPltPos.getOrderWidth())
                            .setWgt(pmProContFilterResposeDTO.getOrderUnitAimWt())
                            .setWholeBacklogCode(getWholeBacklogCode(axisPmProCont, pmProContYield))
                            .setStNo(pmProContFilterResposeDTO.getStNo())
                            .setSgSign(pmProContFilterResposeDTO.getSgSign())
                            .setProcCd(getProcCd()));
        }
        eventClient.addEvent(getCtEventCode(), boardEndEventList);
    }
    
    @Override
    protected String getCtEventCode() {
        return CtEventConstants.EVENT_PM_CONTRACT_RESIDUE_BOARD_END;
    }
    
    @Override
    protected String getWholeBacklogCode(PmProContFilterResposeDTO axisPmProCont,
            PmProContYieldRequestDTO pmProContYield) {
        return Constants.WholeBacklogCode.CODE_13;
    }
    
    @Override
    protected String getProcCd() {
        return Constants.ProdcCd.CD_13B;
    }

    @Override
    protected Long ctEventBoardPpFlag(PmPdPlate t, PmProContYieldRequestDTO pmProContYield) {
        return PdProdFlag.ACTUAL_COMPOSITE_SLAB.getCode();
    }
    
    @Override
    protected Long getSmallPosPpFlag() {
        return PdProdFlag.ACTUAL_SUB_SLAB.getCode();
    }
    
    @Override
    public List<PmBoardMatInfoDTO> selectBoardMatByOrderNo(String orderNo, Long organizationId) {
        MmPlateVO queryParam = new MmPlateVO();
        queryParam.setTenantId(organizationId);
//        queryParam.setOrderNo(orderNo);
        queryParam.setMatStatusList(Lists.newArrayList("39", "29"));
        List<MmPlateVO> mmPlates = mmPlateRepository.selectList(queryParam);

        List<MmPlateVO> filterMmPlateList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(mmPlates)) {
            filterMmPlateList = mmPlates.stream().filter(item -> !"4".equals(item.getComplexDecideCode()))
                    .collect(Collectors.toList());
        }

        PmProContProdTtr record = new PmProContProdTtr();
        record.setOrderNo(orderNo);
        record = this.pmProContProdTtrRepository.selectOne(record);

        if (record == null) {
            return new ArrayList<>();
        }

        PmContMscTech pmContMscTech = new PmContMscTech();
        pmContMscTech.setOrderNo(orderNo);
        List<PmContMscTech> pmContMscTechs = this.pmContMscTechRepository.select(pmContMscTech);
        if (pmContMscTechs == null || pmContMscTechs.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, PmContMscTech> pmContMscTechMap = Maps.uniqueIndex(pmContMscTechs, PmContMscTech::getMscLineNo);
        List<String> rollLineNoList = new ArrayList<>();
        List<String> matNoList = new ArrayList<>();
        for (MmPlateVO mmPlateVO : filterMmPlateList) {
            if (pmContMscTechMap.containsKey(mmPlateVO.getMscLineNo())) {
                rollLineNoList.add(Utils.mscLineNoToRoolLineNo(mmPlateVO.getMscLineNo()));
            }
            matNoList.add(mmPlateVO.getMatNo());
        }
        if (rollLineNoList == null || rollLineNoList.isEmpty()) {
            return new ArrayList<>();
        }
        // 查询组板状态值
        List<PmPdPlate> pmPdPlateList = pmPdPlateRepository.selectByCondition(
                Condition.builder(PmPdPlate.class).andWhere(Sqls.custom().andIn(PmPdPlate.FIELD_PLATE_NO, matNoList))
                        .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_TENANT_ID, organizationId)).build());
        Map<String, PmPdPlate> pmPdPlateMap = new HashMap<>(pmPdPlateList.size());
        if (CollectionUtils.isNotEmpty(pmPdPlateList)) {
            pmPdPlateMap = Maps.uniqueIndex(pmPdPlateList, PmPdPlate::getPlateNo);
        }
        List<PmSlabSpecBt> pmSlabSpecBts = pmSlabSpecBtRepository
                .selectByCondition(Condition.builder(PmSlabSpecBt.class)
                        .andWhere(Sqls.custom().andIn(PmSlabSpecBt.FIELD_ROLL_LINE_NO, rollLineNoList)
                                .andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, organizationId)
                                .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, CcType.TYPE_1))
                        .build());
        if (pmSlabSpecBts == null || pmSlabSpecBts.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, List<PmSlabSpecBt>> pmSlabSpecBtMap = pmSlabSpecBts.stream()
                .collect(Collectors.groupingBy(PmSlabSpecBt::getRollLineNo));

        List<PmBoardMatInfoDTO> pmBoardMatInfoDTOs = new ArrayList<PmBoardMatInfoDTO>();
        for (MmPlateVO mmPlateVO : filterMmPlateList) {

            if (!pmContMscTechMap.containsKey(mmPlateVO.getMscLineNo())) {
                continue;
            }

            PmProContFilterResposeDTO pmProContFilterResposeDTO = BeanUtils.copy(record,
                    PmProContFilterResposeDTO.class);
            pmProContFilterResposeDTO = BeanUtils.copy(pmContMscTechMap.get(mmPlateVO.getMscLineNo()),
                    pmProContFilterResposeDTO);
            String rollLineNo = Utils.mscLineNoToRoolLineNo(mmPlateVO.getMscLineNo());
            PmProContFilterRequestDTO pmProContFilterRequest = new PmProContFilterRequestDTO();
            pmProContFilterRequest.setTenantId(organizationId);
            pmProContFilterRequest.setCcType(CcType.TYPE_1);
            pmProContFilterRequest.setFurType(BaseConstants.Flag.YES.toString());
            pmProContFilterRequest.setStNo(mmPlateVO.getStNo());
            pmProContFilterRequest.setRollDirectCode(pmProContFilterResposeDTO.getRollDirectCode());
            pmProContFilterRequest.setMatDesignKind(PdMatType.P.getCode());
            pmProContFilterRequest.setMoldThick(mmPlateVO.getMatActThk());
            pmProContFilterRequest.setMoldWidth(mmPlateVO.getMatActWid());

            if (!contFilterRuleSetCheck(pmProContFilterRequest, pmProContFilterResposeDTO,
                    pmSlabSpecBtMap.get(rollLineNo), null)) {
                continue;
            }

            PmBoardMatInfoDTO pmBoardMatInfoDTO = new PmBoardMatInfoDTO();
            pmBoardMatInfoDTO.setPlateId(mmPlateVO.getPlateId());
            pmBoardMatInfoDTO.setMatActLength(mmPlateVO.getMatActLen());
            pmBoardMatInfoDTO.setMscLineNo(mmPlateVO.getMscLineNo());
            pmBoardMatInfoDTO.setSlabNo(mmPlateVO.getSlabNo());
            pmBoardMatInfoDTO.setMatNo(mmPlateVO.getMatNo());
            pmBoardMatInfoDTO.setMatStatus(mmPlateVO.getMatStatus());
            pmBoardMatInfoDTO.setMatActLen(mmPlateVO.getMatActLen());
            pmBoardMatInfoDTO.setMatActThick(mmPlateVO.getMatActThk());
            pmBoardMatInfoDTO.setMatActThk(mmPlateVO.getMatActThk());
            pmBoardMatInfoDTO.setMatActWid(mmPlateVO.getMatActWid());
            pmBoardMatInfoDTO.setMatActThk(mmPlateVO.getMatActThk());
            pmBoardMatInfoDTO.setSgSign(mmPlateVO.getSgSign());
            pmBoardMatInfoDTO.setStNo(mmPlateVO.getStNo());
            pmBoardMatInfoDTO.setHoldCauseCode(mmPlateVO.getHoldCauseCode());
            pmBoardMatInfoDTO.setComplexDecideCode(mmPlateVO.getComplexDecideCode());
            pmBoardMatInfoDTO.setFurType("C");
            pmBoardMatInfoDTO.setMatActWgt(mmPlateVO.getMatActWgt());
            pmBoardMatInfoDTO.setOuStatusHp("00");
            if (pmPdPlateMap.containsKey(mmPlateVO.getMatNo())) {
                pmBoardMatInfoDTO.setOuStatusHp(pmPdPlateMap.get(mmPlateVO.getMatNo()).getPdStatusHp());
            }
            pmBoardMatInfoDTOs.add(pmBoardMatInfoDTO);
        }
        return pmBoardMatInfoDTOs;
    }

    @Override
    public void callMatStatusModify(PmPdPlate pmPdPlate, Long tenantId) {
        // 查询mm_plate查询
//       List<MmPlateVO> mmPlateVOList = mmPlateRepository.getMmPlateByMatNo(Lists.newArrayList(pmPdPlate.getPlateNo()), tenantId);
        MmPlateVO mmPlate = mmPlateRepository.selectByPrimary(pmPdPlate.getMmPlateId());
        if(mmPlate == null) {
            throw new CommonException("pm.pm_pd_plate_001");
        }
        MatStatusModifyVO matStatusModifyVO = new MatStatusModifyVO();
        matStatusModifyVO.setMatNo(pmPdPlate.getPlateNo());
        matStatusModifyVO.setPpFlag(mmPlate.getProdCd());
        //余材29 39都调用 轧钢
        log.info("<=====余材钢板组板29/39调用: dtoList = {}", JSONObject.toJSON(matStatusModifyVO));
        mmEventClient.matStatusModify(tenantId, Constants.EventCode.MM_PM_PROD_MANAGEMENT_BLOCKED_IN_PROCESS_MATERIAL,
                matStatusModifyVO);
        /*if ("39".equals(mmPlateVOList.get(0).getMatStatus())) {
            // 39-31
            log.info("<=====余材钢板组板39调用: dtoList = {}", JSONObject.toJSON(matStatusModifyVO));
            mmEventClient.matStatusModify(tenantId, Constants.EventCode.MM_PROD_MANAGEMENT_BLOCKED_END_PROCESS_MATERIAL,
                    matStatusModifyVO);
        } else {
            log.info("<=====余材钢板组板29调用: dtoList = {}", JSONObject.toJSON(matStatusModifyVO));
            mmEventClient.matStatusModify(tenantId, Constants.EventCode.MM_PM_PROD_MANAGEMENT_BLOCKED_IN_PROCESS_MATERIAL,
                    matStatusModifyVO);
        }*/
    }
}
