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

import com.xisc.pm.api.dto.RuleParamDTO;
import com.xisc.pm.app.service.strategy.RuleExecStrategyFactory;
import com.xisc.pm.domain.entity.PmPdConstBt;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.repository.PmPdConstBtRepository;
import com.xisc.pm.domain.repository.PmSlabSpecBtRepository;
import com.xisc.pm.infra.constant.Constants.RollDirectCode;
import com.xisc.pm.infra.constant.PmPlateConstants;
import com.xisc.pm.infra.constant.RuleSetConstants;
import com.xisc.pm.infra.enums.PdRuleItemType;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.exception.CommonException;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;

/**
 * 板坯可轧制宽度上下限检查
 * 
 * 获取传入合同号order_no，根据合同号从生产合同产品属性表PM_PRO_CONT_PROD_ATTR获取合同订货宽度ORDER_WIDTH，合同订货厚度ORDER_THICK。
 * 根据板坯厚度起止SLAB_THICK_FROM/TO包含mold_thick，轧制方向代码等于输入roll_direct_code，板坯宽度起止SLAB_WIDTH_FROM/TO包含mold_width，
 * 轧制产线号等于去向产线号后两位，从连铸板坯生产规格基准表获取精轧最小厚度MIN_ROLL_THICK，可轧制宽度下限CAN_ROLL_WIDTH_MIN，计算mold_thick
 * / (ORDER_THICK + MIN_ROLL_THICK) * mold_width
 * 记作A，根据轧制产线号从组板常数基准表PM_PD_CONST_BT读取厚板设备限制轧制大板最大宽度HPM_MAX_P_WIDTH.
 * 轧制宽度工艺上限等于Min(HPM_MAX_P_WIDTH, A).
 * 若合同订货宽度大于轧制宽度工艺上限，提示信息：合同【ORDER_NO】的订货宽度【ORDER_WIDTH】大于轧制宽度工艺上限【Min(CAN_ROLL_WIDTH_MAX,
 * mold_thick / (ORDER_THICK + MIN_ROLL_THICK) * mold_width)】.
 * 若合同订货宽度小于可轧制宽度下限，提示信息：合同【ORDER_NO】的订货宽度【ORDER_WIDTH】小于可能轧制宽度下限【CAN_ROLL_WIDTH_MIN】.
 * 
 * @author jun.zeng
 *
 */
@Component
public class SlabRollWidthMatchRuleExecStrategy implements RuleExecStrategy {
    
    @Autowired
    private PmPdConstBtRepository pmPdConstBtRepository ;
    
    @Autowired
    private PmSlabSpecBtRepository pmSlabSpecBtRepository;

    @Override
    public void afterPropertiesSet() throws Exception {
        RuleExecStrategyFactory.register(PdRuleItemType.SLAB_ROLL_WIDTH_MATCH, this);
    }

    @Override
    public boolean execRule(RuleParamDTO ruleParam) {
        Map<String, Object> bizData = ruleParam.getBizData();
        String orderNo = (String) bizData.get(RuleSetConstants.ORDER_NO);
        String mscLineNo = (String) bizData.get(RuleSetConstants.MSC_LINE_NO);
        String ccType = (String) bizData.get(RuleSetConstants.CC_TYPE);
        // 结晶器厚度
        BigDecimal moldThick = (BigDecimal) bizData.get(RuleSetConstants.MOLD_THICK);
        BigDecimal moldWidth = (BigDecimal) bizData.get(RuleSetConstants.MOLD_WIDTH);
        BigDecimal combinePlateWidth = (BigDecimal) bizData.get(RuleSetConstants.COMBINE_PLATE_WIDTH);
        Integer rsCode = (Integer) bizData.get(RuleSetConstants.RS_CODE);
        String rollDirectCode = rsCode == 3 ? RollDirectCode.L : RollDirectCode.C ;
        PmPdConstBt record = new PmPdConstBt();
        record.setTenantId(ruleParam.getTenantId());
        record.setRollLineNo(Utils.mscLineNoToRoolLineNo(mscLineNo));
        // 厚板设备限制轧制大板最大长度为【HPM_MAX_P_LEN】。
        record = pmPdConstBtRepository.selectOne(record);
        if(record == null) {
            throw new CommonException("pm.pm_pd_const_bt_002", mscLineNo);
        }
        
        PmProContProdTtr pmProContProdTtr = (PmProContProdTtr) bizData.get(RuleSetConstants.AXIS_PM_PRO_CONT_PROD_ATTR);
        
        if (null == pmProContProdTtr) {
            // 生产合同池没有找到记录，合同号【order_no】，产线号【msc_line_no】。
            throw new CommonException("pm.pm_pd_rule_set_001", orderNo, mscLineNo);
        }
        
        List<PmSlabSpecBt> pmSlabSpecBts = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, ruleParam.getTenantId())
                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(mscLineNo))
                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCode)
                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_TO, moldThick)
                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_FROM, moldThick)
                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_TO, moldWidth)
                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_FROM, moldWidth)
                        .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, ccType))
                .build());
        
        if (null == pmSlabSpecBts || pmSlabSpecBts.isEmpty()) {
            // 读连铸板坯生产规格基准表没有找到记录，连铸机类型【CC_TYPE】，钢板厚度【ORDER_THICK】，轧制产线号【msc_line_no后两位】
            throw new CommonException("pm.pm_pd_rule_set_004", ccType, moldThick.toPlainString(), moldWidth, mscLineNo, rollDirectCode, PdRuleItemType.SLAB_ROLL_WIDTH_MATCH.getCode());
        }
        BigDecimal minRollThick = null; 
        BigDecimal canRollWidthMin = null;
        
        for (PmSlabSpecBt pmSlabSpecBt : pmSlabSpecBts) {
            if(minRollThick == null || minRollThick.compareTo(pmSlabSpecBt.getMinRollThick()) > 0) {
                minRollThick = pmSlabSpecBt.getMinRollThick();
                canRollWidthMin = pmSlabSpecBt.getCanRollWidthMin();
            }
        }
        if (null == minRollThick || canRollWidthMin == null) {
            // 读连铸板坯生产规格基准表没有找到记录，连铸机类型【CC_TYPE】，钢板厚度【ORDER_THICK】，轧制产线号【msc_line_no后两位】
            throw new CommonException("pm.pm_pd_rule_set_004", ccType, moldThick.toPlainString(), moldWidth, mscLineNo, rollDirectCode, PdRuleItemType.SLAB_ROLL_WIDTH_MATCH.getCode());
        }
        
        // mold_thick / (ORDER_THICK + MIN_ROLL_THICK) * mold_width
        BigDecimal ratioRollWidth = moldThick.divide(pmProContProdTtr.getOrderThick().add(minRollThick) , PmPlateConstants.TEM_SCALE , RoundingMode.HALF_UP).multiply(moldWidth);
        BigDecimal widthLimit = Utils.minValue(record.getHpmMaxPWidth() , ratioRollWidth);
        if(canRollWidthMin.compareTo(combinePlateWidth) > 0) {
            throw new CommonException("pm.pm_pd_rule_set_041", combinePlateWidth.toPlainString() , canRollWidthMin.toPlainString());
        }
        if(widthLimit.compareTo(combinePlateWidth) < 0) {
            throw new CommonException("pm.pm_pd_rule_set_042", combinePlateWidth.toPlainString() , widthLimit.toPlainString());
        }

        

        return true;
    }

}
