package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step.method;

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionCustomContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionDispatchContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCell;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StationResultBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description : 加工单验证工单完成数量通用工步方法
 * @Author : wangjie
 **/
@Slf4j
@Service("mesWorkOrderCheckCompleteQtyStepService")
public class MesWorkOrderCheckCompleteQtyStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    //验证加工单完成数量, 验证的前提条件: 每腔均已匹配到加工规则;存在工单;
    public List<MesWorkOrderCompleteQtyContext> dispatchWorkOrderCompleteQtyContext(StationRequestBean reqBean, StationResultBean resultBean,
                                                                                    StepResult stepResult, MesProductionProcessContext productionProcessContext,
                                                                                    List<MesProductionPartContext> productionPartContextList, List<MesProductionPsInContext> productionPsInContextList) {
        //是否存在产成零件信息
        if (!stepResult.isCompleted() || CollectionUtils.isEmpty(productionPartContextList)) return null;

        //根据产出零件或者腔数拿到需要的加工规则数量, 优先使用产出零件数量
        Integer needQty = !CollectionUtils.isEmpty(productionPartContextList) ? productionPartContextList.size() : productionProcessContext.getCurCellEquip().getCavity();
        //验证是否满足腔数
        if (!CollectionUtils.isEmpty(productionPsInContextList) && productionPsInContextList.size() < needQty) return null;

        //对MesProductionPartContext中的工单号经行分组，每个工单可能对应多条数据, 筛选掉foreignkey为空的数据
        Map<String, List<MesProductionPartContext>> productionPartContextMap = productionPartContextList.stream().filter(o ->
                (!StringUtils.isEmpty(o.getWorkOrderNo()) && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.groupingBy(MesProductionPartContext::getWorkOrderNo));

        if (CollectionUtils.isEmpty(productionPartContextMap)) return null;

        //根据foreignkey分组进料零件条码
        Map<Integer, MesProductionPsInContext> productionPsInContextMap = CollectionUtils.isEmpty(productionPsInContextList) ? null :
                productionPsInContextList.stream().filter(o -> !StringUtils.isEmpty(o.getForeignKey())).collect(Collectors.toMap(MesProductionPsInContext::getForeignKey, o -> o));

        //生产线与工位信息
        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();
        MesWorkCell workCell = productionProcessContext.getWorkCell();
        //工位是否不累计工单完成数
        Boolean noCalcOrderQty = noCalcOrderQty(workCell.getNoCalcOrderQty());

        //遍历验证加工单完成数量
        List<MesWorkOrderCompleteQtyContext> workOrderCompleteQtyContextList = null;
        for (Map.Entry<String, List<MesProductionPartContext>> entry : productionPartContextMap.entrySet()) {
            if (null == entry) continue;

            //验证加工单完成数量
            MesWorkOrderCompleteQtyContext workOrderCompleteQtyContext = dispatchWorkOrderCompleteQty(reqBean, resultBean, stepResult, workCenter, noCalcOrderQty, entry.getValue(), productionPsInContextMap);

            //验证失败直接退出
            if (!stepResult.isCompleted()) break;

            if (null != workOrderCompleteQtyContext) {
                if (CollectionUtils.isEmpty(workOrderCompleteQtyContextList)) workOrderCompleteQtyContextList = new ArrayList<>();
                workOrderCompleteQtyContextList.add(workOrderCompleteQtyContext);
            }

        }

        //验证失败标记删除标志
        if (!stepResult.isCompleted()) {
            productionPartContextList.forEach(o -> o.busiCheckToDelete());
            if (!CollectionUtils.isEmpty(productionPsInContextList)) productionPsInContextList.forEach(o -> o.busiCheckToDelete());
            if (!CollectionUtils.isEmpty(workOrderCompleteQtyContextList)) workOrderCompleteQtyContextList.clear();
        }

        return workOrderCompleteQtyContextList;

    }

    //验证加工单完成数量
    private MesWorkOrderCompleteQtyContext dispatchWorkOrderCompleteQty(StationRequestBean reqBean, StationResultBean resultBean,
                                                                        StepResult stepResult, MesWorkCenter workCenter, Boolean noCalcOrderQty,
                                                                        List<MesProductionPartContext> productionPartContextList, Map<Integer, MesProductionPsInContext> productionPsInContextMap) {
        Double calcCompleteQty = new Double(MesPcnExtConstWords.ZERO);
        for (MesProductionPartContext productionPartContext : productionPartContextList) {
            MesProductionPsInContext productionPsInContext = getProductionPsInContext(productionPsInContextMap, productionPartContext.getForeignKey());
            //验证进料零件与产出零件是否一致
            Boolean isSamePart = isSamePart(productionPsInContext, productionPartContext, null);
            //验证是否计数
            Boolean isCalcCompleteQty = isCalcCompleteQty(isSamePart, productionPsInContext, productionPartContext);
            if (isCalcCompleteQty) calcCompleteQty = MathOperation.add(calcCompleteQty, new Double(MesPcnExtConstWords.ONE));
        }
        //当前工单无须计算工单完成数
        if (MathOperation.compareTo(calcCompleteQty, new Double(MesPcnExtConstWords.ZERO)) == 0) return null;

        //根据noCalcOrderQty判断维度处理工单完成数上下文[查询]【noCalcOrderQty=true代表工位维度的统计,最终不会实际累加到工单上】【noCalcOrderQty=false代表生产线维度的统计,才会实际累加到工单上】
        MesWorkOrderCompleteQtyContext workOrderCompleteQtyContext = productionCustomContextStepService.dispatchWorkOrderCompleteQtyContext(reqBean, noCalcOrderQty, productionPartContextList.get(0));

        //验证工单完成数
        checkWorkOrderCompleteQty(reqBean, resultBean, stepResult, workCenter, workOrderCompleteQtyContext, calcCompleteQty, noCalcOrderQty);

        if (!stepResult.isCompleted()) return null;

        return workOrderCompleteQtyContext;

    }

    //工位是否不累计工单完成数
    public Boolean noCalcOrderQty(Integer noCalcOrderQty) {
        return (!StringUtils.isEmpty(noCalcOrderQty) && noCalcOrderQty.compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) ? true : false;
    }

    //验证进料零件与产出零件是否一致
    public Boolean isSamePart(MesProductionPsInContext productionPsInContext, MesProductionPartContext productionPartContext, MesProdRuleContext prodRuleContext) {
        if (null == productionPsInContext) return false;
        if (StringUtils.isEmpty(productionPsInContext.getPartNo())) return false;
        if (null != productionPartContext) {
            if (!productionPsInContext.getPartNo().equals(productionPartContext.getPartNo())) return false;
            else return true;
        } else {
            if (!productionPsInContext.getPartNo().equals(prodRuleContext.getOutPartNo())) return false;
            else return true;
        }
    }

    //验证是否计数
    public Boolean isCalcCompleteQty(Boolean isSamePart, MesProductionPsInContext productionPsInContext, MesProductionPartContext productionPartContext) {
        //未选工单场景
        if (null == productionPartContext || StringUtils.isEmpty(productionPartContext.getWorkOrderNo())) return false;
        //进出不一致
        if (!isSamePart) return true;
        //进出一致的情况下: 【打印件已经是产成的情况下也需要计数】
        if (!StringUtils.isEmpty(productionPsInContext.getId()) && StringUtils.isEmpty(productionPsInContext.getProcessCode()) &&
                !StringUtils.isEmpty(productionPsInContext.getPrintStatus()) && productionPsInContext.getPrintStatus().compareTo(MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue()) == 0) {
            return true;
        }
        //进出一致
        return false;
    }

    //根据数据关联键获取进料零件信息
    private MesProductionPsInContext getProductionPsInContext(Map<Integer, MesProductionPsInContext> productionPsInContextMap, Integer foreignKey) {
        if (CollectionUtils.isEmpty(productionPsInContextMap) || StringUtils.isEmpty(foreignKey)) return null;
        return productionPsInContextMap.get(foreignKey);
    }

    //验证工单完成数
    private void checkWorkOrderCompleteQty(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesWorkCenter workCenter,
                                           MesWorkOrderCompleteQtyContext workOrderCompleteQtyContext, Double calcCompleteQty, Boolean noCalcOrderQty) {

        //当前工序的预计达到的完成数
        Double complateQty = MathOperation.add(workOrderCompleteQtyContext.getCompleteQty(), calcCompleteQty);
        // 如果预完成数量 小于等于工单数量，则直接过
        if (MathOperation.compareTo(workOrderCompleteQtyContext.getQty(), complateQty) >= 0) return;
        //判断不支持超工单生产
        if (StringUtils.isEmpty(workCenter.getIsCheckOrderQty()) || workCenter.getIsCheckOrderQty().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0) {
            //stepResult.obj(false)目的是在工步最后可以判断是否需要清除进料
            stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult.obj(false), String.format("请检查工单数量,工单[%s]计划数量[%s]%s已完成数量[%s]!",
                    workOrderCompleteQtyContext.getWorkOrderNo(), workOrderCompleteQtyContext.getQty().intValue(),
                    noCalcOrderQty ? "当前工位" : MesPcnExtConstWords.EMPTY, workOrderCompleteQtyContext.getCompleteQty().intValue(),
                    MathOperation.compareTo(workOrderCompleteQtyContext.getQty(), workOrderCompleteQtyContext.getCompleteQty()) == 0 ? "当前已完成!" : "当前不支持超工单!"));
            return;
        }
        //支持超工单生产情况下判断超出比例
        Double rate = MathOperation.div((MathOperation.sub(complateQty, workOrderCompleteQtyContext.getQty())), workOrderCompleteQtyContext.getQty());
        if (MathOperation.compareTo(rate, MathOperation.div(workCenter.getOrderRate(), new Double(MesPcnExtConstWords.ONE_HUNDRED))) > 0) {
            stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult.obj(false), String.format("请检查工单数量,工单[%s]计划数量[%s]%s已完成数量[%s]超工单比例[%s]!",
                    workOrderCompleteQtyContext.getWorkOrderNo(), workOrderCompleteQtyContext.getQty().intValue(),
                    noCalcOrderQty ? "当前工位" : MesPcnExtConstWords.EMPTY, workOrderCompleteQtyContext.getCompleteQty().intValue(), workCenter.getOrderRate()));
            return;
        }
    }

    //清除本次扫描/读取信息   有进料【只】需要清除进料,否则存在产出零件需要清除产出零件 【只需要清除被标记的数据】
    public Boolean doBusiCheckToDelete(StationRequestBean reqBean, StepResult stepResult, List<MesProductionPartContext> productionPartContextList, List<MesProductionPsInContext> productionPsInContextList) {
        if (!CollectionUtils.isEmpty(productionPsInContextList) && StringUtils.isEmpty(stepResult.getObj())) {
            productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList.stream().filter(o -> (null != o && o.getBusiCheckToDelete().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0)).collect(Collectors.toList()));
        } else if (!CollectionUtils.isEmpty(productionPartContextList)) {
            if (!StringUtils.isEmpty(stepResult.getObj())) productionDispatchContextStepService.removeProductionPsInContext(reqBean);
            productionDispatchContextStepService.removeProductionPartContext(reqBean);
            productionDispatchContextStepService.removeProdRuleDataContext(reqBean);
            productionProcessContextStepService.removeFunctionChooseCavityOrderContext(reqBean);
            if (productionDispatchContextStepService.checkFirstMouldNoIsExistContext(reqBean)) {
                //存在头道模具号场景下 必须抛出异常 因为头道模具号的接口逻辑会配置非常变值,也就是每次返回回去都会拿到头道模具号 就会出现死循环线程
                productionDispatchContextStepService.removeFirstMouldNoContext(reqBean);
                foundExThrowNoShowMsg();
            }
        }
        return true;
    }

}
