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.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.actor.shipping.dispatch.IFsmCommonService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
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 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.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Description : 装配件匹配工步 【排序】
 * @Author : wangjie
 **/
@Slf4j
@Service("mesAssemblyMatchSortStepService")
public class MesAssemblyMatchSortStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesNumberRuleMatchDispatchService numberRuleMatchDispatchService;

    @Autowired
    private IMesProductionRecordService productionRecordService;

    @Autowired
    private IMesTimeEfficientCfgMatchService timeEfficientCfgMatchService;

    @Autowired
    private IFsmCommonService fsmCommonService;

    @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());

        //存储生产过程上下文对象
        productionProcessContextStepService.dispatchProductionProcessContext(reqBean, productionProcessContext);

        //获取加工结果
        String productResult = productionDispatchContextStepService.getProductResultContext(reqBean);
        if (!StringUtils.isEmpty(productResult) && !productResult.equals(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue() + MesPcnExtConstWords.EMPTY) &&
                (StringUtils.isEmpty(productionProcessContext.getWorkCenter().getIsIgnoreQc())
                        || productionProcessContext.getWorkCenter().getIsIgnoreQc().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) != 0)) {
            return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult,
                    String.format("加工单质量状态标记[%s],当前装配件清单默认跳过!", MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(Integer.parseInt(productResult))),
                    MesPcnEnumUtil.PROMPT_SOUND.SUCCESS.getValue());
        }

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

        //判断是否存在装配件清单
        if (!checkIsNeedScanAssembly(prodRuleContextList)) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, true,
                    MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, "当前加工规则无装配件清单,当前无需匹配装配件条码!");
        }

        //验证是否存在待绑定数据
        Boolean hasUnBindAssembly = hasUnBindAssembly(prodRuleContextList);
        if (!hasUnBindAssembly) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, true,
                    MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, "当前加工规则对应的装配件清单均匹配完毕!");
        }

        //获取上下文生产扫/读信息:装配件条码
        List<MesEquipVariableCollectContext> equipVariableCollectContextList = productionDispatchContextStepService.getScanAssemblySnContext(reqBean);
        if (CollectionUtils.isEmpty(equipVariableCollectContextList)) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult.nextTriggerEvent(MesPcnExtConstWords.NEXT_TRIGGER_EVENT_ASSEMBLY), "当前不存在装配件条码!");

        //删除上下文扫/读信息:装配件条码
        productionDispatchContextStepService.removeScanAssemblySnContext(reqBean);

        //验证当前是否属于装配件跳过码
        Boolean isSkip = checkIsSkip(productionProcessContext, equipVariableCollectContextList);
        //验证当前是否属于装配件整腔跳过码
        Boolean isCavitySkip = checkIsCavitySkip(productionProcessContext, equipVariableCollectContextList);

        //处理待验证的装配件条码 [扫描模式匹配成功返回true, 否则返回flase, 非扫描模式需要验证是否全部匹配完成]
        Boolean result = doHandleMatchAssembly(reqBean, resultBean, stepResult, productionProcessContext.getWorkCenter(), prodRuleContextList, equipVariableCollectContextList, isSkip, isCavitySkip);

        //验证是否存在待绑定数据
        hasUnBindAssembly = hasUnBindAssembly(prodRuleContextList);

        //搜集装配件条码
        String suffix = MesPcnExtConstWords.EMPTY;
        String assemblySn = equipVariableCollectContextList.stream().filter(o -> null != o).map(MesEquipVariableCollectContext::getEquipVariableValue).collect(Collectors.toList()).toString();
        //匹配成功 【result=true 代表单次扫描匹配成功; hasUnBindAssembly=false 代表浑腔模式全部匹配成功】
        if (result || !hasUnBindAssembly) {
            //获取上下文产出零件条码信息集合
            List<MesProductionPsOutContext> productionPsOutContextList = productionDispatchContextStepService.getProductionPsOutContext(reqBean);
            //获取上下文工位扫描监控信息
            MesScanMonitorContext scanMonitorContext = productionProcessContextStepService.dispatchScanMonitorContext(reqBean, true);
            //无需扫描的需要先写库, 使用isSaveDb=1 进行标记
            prodRuleContextList = ((MesAssemblySaveSortStepService) SpringContextsUtil.getBean("mesAssemblySaveSortStepService")).saveSortProductionAssembly(reqBean, prodRuleContextList, productionPsOutContextList, scanMonitorContext);
            productionDispatchContextStepService.dispatchProdRuleDataContext(reqBean, prodRuleContextList);
            ((MesAssemblyShowSortStepService) SpringContextsUtil.getBean("mesAssemblyShowSortStepService")).showProductionAssembly(reqBean, resultBean, productionProcessContext.getWorkCenter(), prodRuleContextList, true, true);
            suffix = (isSkip || isCavitySkip) ? stepResult.getMsg() : String.format("装配件条码%s匹配成功!", assemblySn);
        }

        //验证是否存在待绑定数据
        if (!hasUnBindAssembly) {
            return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, String.format("%s当前加工规则对应的装配件清单均匹配完毕!", suffix),
                    MesPcnEnumUtil.PROMPT_SOUND.SUCCESS.getValue());
        }

        //单次匹配成功
        if (result) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog().scanInfo(assemblySn),
                    stepResult.nextTriggerEvent(MesPcnExtConstWords.NEXT_TRIGGER_EVENT_ASSEMBLY), false, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, suffix,
                    MesPcnEnumUtil.PROMPT_SOUND.SUCCESS.getValue());
        }

        suffix = String.format("装配件条码%s匹配失败!", assemblySn);

        this.sendMessage(reqBean, new StationResultBean().writeDbLog().scanInfo(assemblySn),
                String.format("%s%s%s", suffix, StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg(), StringUtils.isEmpty(stepResult.getObj()) ? MesPcnExtConstWords.EMPTY : stepResult.getObj()),
                MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);

        stepResult.msg(String.format("%s%s", suffix, !StringUtils.isEmpty(stepResult.getMsg()) ? stepResult.getMsg() : (
                (StringUtils.isEmpty(stepResult.getObj()) || !checkWcpcMapIsMatch(reqBean, MesPcnExtConstWords.ASSEMBLY_SHOW_MR_CFG)) ? MesPcnExtConstWords.EMPTY : (
                        (!stepResult.getObj().toString().contains(MesPcnExtConstWords.EXCLAMATION) ||
                                stepResult.getObj().toString().indexOf(MesPcnExtConstWords.EXCLAMATION) != stepResult.getObj().toString().lastIndexOf(MesPcnExtConstWords.EXCLAMATION)
                        ) ? MesPcnExtConstWords.EMPTY : stepResult.getObj()))
                )
        );

        return stepNonCompleteAndSendMsgReturn(reqBean, resultBean, stepResult.nextTriggerEvent(MesPcnExtConstWords.NEXT_TRIGGER_EVENT_ASSEMBLY), stepResult.getMsg());

    }

    //验证当前是否属于装配件跳过码
    private Boolean checkIsSkip(MesProductionProcessContext productionProcessContext, List<MesEquipVariableCollectContext> equipVariableCollectContextList) {
        if (equipVariableCollectContextList.size() > 1) return false;
        if (equipVariableCollectContextList.get(0).getMessageSource().compareTo(MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue()) != 0) return false;
        if (!equipVariableCollectContextList.get(0).getEquipVariableValue().equals(productionProcessContext.getAssemblySkipCode())) return false;
        return true;
    }

    //验证当前是否属于装配件整腔跳过码
    private Boolean checkIsCavitySkip(MesProductionProcessContext productionProcessContext, List<MesEquipVariableCollectContext> equipVariableCollectContextList) {
        if (equipVariableCollectContextList.size() > 1) return false;
        if (equipVariableCollectContextList.get(0).getMessageSource().compareTo(MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue()) != 0) return false;
        if (!equipVariableCollectContextList.get(0).getEquipVariableValue().equals(productionProcessContext.getAssemblyCavitySkipCode())) return false;
        return true;
    }

    //判断是否存在装配件清单
    private Boolean checkIsNeedScanAssembly(List<MesProdRuleContext> prodRuleContextList) {
        Optional<MesProdRuleContext> optional = prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAssemblyDataJson()))).findFirst();
        return (null == optional || !optional.isPresent()) ? false : true;
    }

    //验证是否存在待绑定数据
    private Boolean hasUnBindAssembly(List<MesProdRuleContext> prodRuleContextList) {
        Boolean hasUnBindAssembly = false;
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getAssemblyDataJson())) continue;
            List<MesProductionAssemblySortContext> productionAssemblySortContextList = prodRuleContext.getSortAssemblyDataContext();
            if (!hasUnBindAssemblyOptional(productionAssemblySortContextList)) continue;
            hasUnBindAssembly = true;
            break;
        }
        return hasUnBindAssembly;
    }

    private Boolean hasUnBindAssemblyOptional(List<MesProductionAssemblySortContext> productionAssemblySortContextList) {
        Optional<MesProductionAssemblySortContext> optional = productionAssemblySortContextList.stream().filter(o -> (null != o && o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) == 0)).findFirst();
        return (null == optional || !optional.isPresent()) ? false : true;
    }

    //处理待验证的装配件条码   [扫描模式匹配成功返回true, 否则返回flase, 非扫描模式需要验证是否全部匹配完成]
    private Boolean doHandleMatchAssembly(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList, List<MesEquipVariableCollectContext> equipVariableCollectContextList, Boolean isSkip, Boolean isCavitySkip) {

        //遍历产品加工规则
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {

            //没有装配件的条件
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getAssemblyDataJson())) continue;

            //获取非排序装配件清单
            List<MesProductionAssemblySortContext> productionAssemblySortContextList = prodRuleContext.getSortAssemblyDataContext();

            Boolean flag = false;

            //遍历装配件清单
            LOOP:
            for (MesProductionAssemblySortContext productionAssemblySortContext : productionAssemblySortContextList) {

                //已装配
                if (null == productionAssemblySortContext || productionAssemblySortContext.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) != 0) continue;

                if (MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.checkIsNeedCustomStepMatch(productionAssemblySortContext.getMatchType()))
                    stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), String.format("当前工序模版不支持匹配[%s]确认方式的装配件信息!", MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.valueOfDescription(productionAssemblySortContext.getMatchType())));

                //遍历装配件条码
                for (MesEquipVariableCollectContext equipVariableCollectContext : equipVariableCollectContextList) {

                    //已被消费
                    if (null == equipVariableCollectContext || equipVariableCollectContext.getIsConsume().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) continue;

                    //装配件跳过, 必须顺序扫描才生效
                    if (isSkip && isCheckBindSeq(prodRuleContext, productionAssemblySortContext)) {

                        //装配件清单该数据标记跳过
                        productionAssemblySortContext.assemblySkip();

                        //匹配成功
                        equipVariableCollectContext.isConsume();
                        stepResult.msg(String.format("装配件跳过码验证成功,已跳过当前装配项!"));

                        flag = true;

                        break LOOP;

                    }

                    //装配件整腔跳过
                    if (isCavitySkip) {

                        //装配件清单该数据标记跳过
                        productionAssemblySortContext.assemblySkip();

                        //判断当腔是否还存在待装配的数据
                        Optional<MesProductionAssemblySortContext> optional = productionAssemblySortContextList.stream().filter(o -> (null != o && o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) == 0)).findFirst();
                        if (null == optional || !optional.isPresent()) {

                            //匹配成功 [整腔全部跳过后标记]
                            equipVariableCollectContext.isConsume();
                            stepResult.msg(String.format("装配件整腔跳过码验证成功,已跳过当腔装配项!"));

                            flag = true;

                            break LOOP;

                        }

                        continue;

                    }

                    //匹配规则
                    Map<String, Object> result = numberRuleMatchDispatchService.matchNumberRule(reqBean.getOrganizeCode(), equipVariableCollectContext.getEquipVariableValue(), productionAssemblySortContext);

                    //匹配失败
                    if (!(Boolean) result.get(MesPcnExtConstWords.RESULT)) {
                        String msg = (String) result.get(MesPcnExtConstWords.MESSAGE);
                        stepResult.obj(String.format("%s%s", StringUtils.isEmpty(stepResult.getObj()) ? MesPcnExtConstWords.EMPTY : stepResult.getObj(), StringUtils.isEmpty(msg) ? MesPcnExtConstWords.EMPTY : msg));
                        continue;
                    }

                    MesProductionAssemblySortContext filter = (MesProductionAssemblySortContext) result.get(MesPcnExtConstWords.DATA);

                    //前道防错
                    if (!StringUtils.isEmpty(filter.getProductSnId()) && !StringUtils.isEmpty(productionAssemblySortContext.getPreCraftCode())) {
                        if (CollectionUtils.isEmpty(productionRecordService.findProductionRecordListByCraft(reqBean.getOrganizeCode(), equipVariableCollectContext.getEquipVariableValue(), productionAssemblySortContext.getPreCraftCode()))) {
                            stepResult.msg(String.format("%s%s", StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg(),
                                    String.format("零件条码[%s]前道防错工艺[%s]验证失败,未查询到加工记录信息!", equipVariableCollectContext.getEquipVariableValue(), productionAssemblySortContext.getPreCraftCode())));
                            continue;
                        }
                    }

                    //时效性验证
                    if (!StringUtils.isEmpty(filter.getProductSnId())) {
                        result = timeEfficientCfgMatchService.checkSnTimeliness(reqBean.getOrganizeCode(), equipVariableCollectContext.getEquipVariableValue(), filter.getPid(), MesExtEnumUtil.TIME_DATA_SOURCE.DATA_SOURCE10.getValue());

                        if (!(Boolean)result.get(MesPcnExtConstWords.RESULT)) {
                            stepResult.msg(String.format("%s%s", StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg(), result.get(MesPcnExtConstWords.MESSAGE)));
                            continue;
                        }
                    }

                    //验证返回result里面是否存在assemblySn,存在特殊的规则会转换成新的条码
                    String assemblySn = !result.containsKey(MesPcnExtConstWords.ASSEMBLY_SN) ? equipVariableCollectContext.getEquipVariableValue() : (String) result.get(MesPcnExtConstWords.ASSEMBLY_SN);

                    //验证规则且唯一/自制件 在当前开模内是否存在重复
                    if (MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.checkUniqueRuleInMould(productionAssemblySortContext.getMatchType()) && !numberRuleMatchDispatchService.checkAssemblySnUniqueInMould(workCenter, prodRuleContextList, assemblySn)) {
                        stepResult.msg(String.format("%s[%s]不能重复装配!", StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg(), assemblySn));
                        continue;
                    }

                    //匹配成功
                    equipVariableCollectContext.isConsume();

                    flag = true;

                    //装配件清单该数据标记已装配 (如果是自制件赋值productSnId)
                    productionAssemblySortContext.assemblyStatus(assemblySn).productSnId(filter.getProductSnId());

                    break;

                }

                //是否验证顺序装配
                if (equipVariableCollectContextList.get(0).getMessageSource().compareTo(MesExtEnumUtil.CELL_MESSAGE_SOURCE.READ.getValue()) != 0 &&
                        isCheckBindSeq(prodRuleContext, productionAssemblySortContext) && productionAssemblySortContext.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) == 0) break;

            }

            //存在匹配成功的数据
            if (flag) prodRuleContext.assemblyDataJson(productionAssemblySortContextList);
            if (flag && equipVariableCollectContextList.get(0).getMessageSource().compareTo(MesExtEnumUtil.CELL_MESSAGE_SOURCE.READ.getValue()) != 0 && equipVariableCollectContextList.size() == 1) return true;

        }

        return false;

    }

    private Boolean isCheckBindSeq(MesProdRuleContext prodRuleContext, MesProductionAssemblySortContext productionAssemblySortContext) {
        if (!StringUtils.isEmpty(prodRuleContext.getIsCheckBindSeq()) && prodRuleContext.getIsCheckBindSeq().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) return true;
        if (!StringUtils.isEmpty(productionAssemblySortContext.getIsCheckBindSeq()) && productionAssemblySortContext.getIsCheckBindSeq().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) return true;
        return false;
    }

    //【工位参数】
    private Boolean checkWcpcMapIsMatch(StationRequestBean reqBean, String paramCode) {
        return fsmCommonService.checkWcpcMapIsMatch(reqBean, paramCode, CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr());
    }

}
