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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesContainerPackageDetailContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionAssemblyContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionProcessContext;
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.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesStation;
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 cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import com.alibaba.fastjson.JSONObject;
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.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description : 站点匹配装配件工步
 * @Author : wangjie
 **/
@Slf4j
@Service("mesStationMatchAssemblyStepService")
public class MesStationMatchAssemblyStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    @Autowired
    private IMesStationContainerSnExtService stationContainerSnExtService;

    @Autowired
    private IMesTimeEfficientCfgMatchService timeEfficientCfgMatchService;

    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StationResultBean resultBean = new StationResultBean();

        StepResult stepResult = StepResult.getSuccessComplete();

        //获取工位当前设备信息
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean);

        //配置错误 抛出异常
        if (!productionProcessContext.getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //获取上下文产品加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);
        if (CollectionUtils.isEmpty(prodRuleContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在产品加工规则信息,请重置工序解决!");

        //验证是否存在装配件容器匹配
        Optional<MesProdRuleContext> optional = prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getIsMatchContainer()))).findFirst();
        if (null == optional || !optional.isPresent()) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, true,
                    MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, "验证每腔不存在容器匹配的装配件,默认跳过站点匹配装配件!");
        }

        //处理设备站点【装配件站点&&混料站点】
        List<MesStation> stationList = productionProcessContextStepService.dispatchEquipmentStationContext(reqBean, productionProcessContext.getCurCellEquip().getEquipmentCode(),
                Stream.of(MesExtEnumUtil.STATION_TYPE.STATION_TYPE_20.getValue(), MesExtEnumUtil.STATION_TYPE.STATION_TYPE_40.getValue()).collect(Collectors.toList()));

        if (CollectionUtils.isEmpty(stationList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "站点匹配装配件时验证设备未关联支持扣减的站点");

        //保存站点用于缺料时进行上料绑定
        productionDispatchContextStepService.dispatchMatchStationContext(reqBean, stationList);

        //获取容器条码上料明细表信息【可扣减】【根据 主表seq,主表createDatetime,明细表createDatetime 正序】
        List<MesContainerPackageDetailContext> containerPackageDetailContextList = stationContainerSnExtService.getContainerPackageDetailContext(reqBean.getOrganizeCode(), stationList);

        if (CollectionUtils.isEmpty(containerPackageDetailContextList)) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(),
                stepResult.nextTriggerEvent(MesPcnExtConstWords.NEXT_TRIGGER_EVENT_FEEDING), "站点匹配装配件时验证当前无可扣减的原材料信息!");

        //将可扣减的条码进行原子性缓存, 并获取最新的实际库存
        productionCustomContextStepService.dispatchContainerPackageDetailAtomicity(reqBean.getOrganizeCode(), containerPackageDetailContextList);

        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();

        //站点信息用于后面扣料业务中进行LOCK
        Map<String, MesStation> stationMap2Lock = new HashMap<>();

        //匹配装配件的工序用量
        dispatchStationMatchAssembly(reqBean, resultBean, stepResult, workCenter, prodRuleContextList, containerPackageDetailContextList, stationMap2Lock);

        if (!stepResult.isCompleted()) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult.nextTriggerEvent(MesPcnExtConstWords.NEXT_TRIGGER_EVENT_FEEDING), stepResult.getMsg());

        //保存上下文产品加工规则信息集合
        productionDispatchContextStepService.dispatchProdRuleDataContext(reqBean, prodRuleContextList);
        //保存站点用于后面扣料业务中进行LOCK
        productionDispatchContextStepService.dispatchLockStationContext(reqBean, stationMap2Lock);

        if (workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0)
            ((MesAssemblyShowNosortStepService) SpringContextsUtil.getBean("mesAssemblyShowNosortStepService")).showProductionAssembly(reqBean, resultBean, workCenter, prodRuleContextList);
        else
            ((MesAssemblyShowSortStepService) SpringContextsUtil.getBean("mesAssemblyShowSortStepService")).showProductionAssembly(reqBean, resultBean, workCenter, prodRuleContextList, true, true);


        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "站点匹配装配件验证成功!");
    }

    //匹配装配件的工序用量【遍历加工规则】
    private void dispatchStationMatchAssembly(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesWorkCenter workCenter,
                                              List<MesProdRuleContext> prodRuleContextList, List<MesContainerPackageDetailContext> containerPackageDetailContextList,
                                              Map<String, MesStation> stationMap2Lock) {
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getIsMatchContainer())) continue;
            List<MesProductionAssemblyContext> productionAssemblyContextList = dispatchStationMatchAssembly(reqBean, resultBean, stepResult, workCenter, prodRuleContext, containerPackageDetailContextList, stationMap2Lock);
            if (!stepResult.isCompleted()) break;
            prodRuleContext.assemblyDataJson(productionAssemblyContextList);
        }
    }

    //匹配装配件的工序用量【遍历装配件】
    private List<MesProductionAssemblyContext> dispatchStationMatchAssembly(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesWorkCenter workCenter,
                                                                            MesProdRuleContext prodRuleContext, List<MesContainerPackageDetailContext> containerPackageDetailContextList,
                                                                            Map<String, MesStation> stationMap2Lock) {
        List<MesProductionAssemblyContext> productionAssemblyContextList = prodRuleContext.getAssemblyDataContext(workCenter);
        for (MesProductionAssemblyContext productionAssemblyContext : productionAssemblyContextList) {
            if (null == productionAssemblyContext || productionAssemblyContext.getMatchType().compareTo(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_80.getValue()) != 0) continue;

            if (StringUtils.isEmpty(productionAssemblyContext.getPartNo()) || StringUtils.isEmpty(productionAssemblyContext.getQty()))
                stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), String.format("当前产成对应的[%s]类型的装配件信息维护零件号或工序用量!", MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_80.getDescription()));

            //未匹配的工序用量
            Double unMatchQty = MathOperation.mul(productionAssemblyContext.getQty(), prodRuleContext.getEachCavityQty());
            //支持被扣减的原料条码
            List<MesContainerPackageDetailContext> containerSnDataList = null;
            //用于给装配件清单赋值
            List<String> barCodeList = null;
            for (MesContainerPackageDetailContext containerPackageDetailContext : containerPackageDetailContextList) {
                if (null == containerPackageDetailContext || StringUtils.isEmpty(containerPackageDetailContext.getPartNo())) continue;
                if (!containerPackageDetailContext.getPartNo().equals(productionAssemblyContext.getAssemblyPartNo()) || MathOperation.compareTo(containerPackageDetailContext.getRemainQty(), new Double(0)) <= 0) continue;

                //验证时效性
                Map<String, Object> result = timeEfficientCfgMatchService.checkSnTimelinessContainerMatch(reqBean.getOrganizeCode(), containerPackageDetailContext,
                        workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0 ? productionAssemblyContext.getSourceId() : productionAssemblyContext.getPid());
                if (!(Boolean)result.get(MesPcnExtConstWords.RESULT)) continue;

                //如果存在未匹配的工序用量
                if (MathOperation.compareTo(unMatchQty, new Double(0)) > 0) {
                    //剩余未匹配的工序用量
                    Double remainQty = MathOperation.sub(containerPackageDetailContext.getRemainQty(), unMatchQty);
                    //全部匹配完成
                    if (MathOperation.compareTo(remainQty, new Double(0)) >= 0) {
                        containerPackageDetailContext.remainQty(remainQty);
                        unMatchQty = new Double(0);
                    } else {
                        //未匹配完成, 0-负数=正数
                        containerPackageDetailContext.remainQty(new Double(0));
                        unMatchQty = MathOperation.sub(new Double(0), remainQty);
                    }
                }
                //将能够扣减的所有条码跟当前装配件关联
                if (CollectionUtils.isEmpty(containerSnDataList)) {
                    containerSnDataList = new ArrayList<>();
                    barCodeList = new ArrayList<>();
                }
                containerSnDataList.add(containerPackageDetailContext);
                barCodeList.add(containerPackageDetailContext.getBarCode());
                if (!stationMap2Lock.containsKey(containerPackageDetailContext.getStation())) stationMap2Lock.put(containerPackageDetailContext.getStation(), containerPackageDetailContext.getStationInfo());
            }

            if (MathOperation.compareTo(unMatchQty, new Double(0)) > 0) {
                if (!StringUtils.isEmpty(productionAssemblyContext.getAssemblySn())) {
                    productionAssemblyContext.setAssemblyStatus(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue());
                    productionAssemblyContext.setAssemblySn(null);
                    productionAssemblyContext.setMatchDatetime(null);
                }
                stepResult.isCompleted(false).msg(String.format("站点匹配装配件时验证零件号[%s]当前缺料,请扫描上料条码!", productionAssemblyContext.getAssemblyPartNo()));
                break;
            } else {
                productionAssemblyContext.setAssemblyStatus(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_10.getValue());
                productionAssemblyContext.setAssemblySn(barCodeList.get(0));
                productionAssemblyContext.setMatchDatetime((new SimpleDateFormat(MesPcnExtConstWords.DATE_FORMAT_SSS)).format(new Date()));
                productionAssemblyContext.setContainerSnData(JSONObject.toJSONString(containerSnDataList));
            }

        }

        return productionAssemblyContextList;
    }

}
