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

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.pojo.context.MesCellEquipContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesEquipVariableCollectContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPartContext;
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.actor.shipping.dispatch.IFsmCommonService;
import cn.estsh.i3plus.mes.pcn.util.StationKvBeanUtil;
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.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.mes.model.StationKvBean;
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.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Description : 加工单验证工步 【非排序】
 * @Author : wangjie
 **/
@Slf4j
@Service("mesWorkOrderCheckNosortStepService")
public class MesWorkOrderCheckNosortStepService extends MesWorkOrderCheckStepService {

    @Autowired
    private IFsmCommonService fsmCommonService;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

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

        //获取上下文生产扫/读信息:加工单
        List<MesEquipVariableCollectContext> equipVariableCollectContextList = productionDispatchContextStepService.getScanWorkOrderNoContext(reqBean);
        if (CollectionUtils.isEmpty(equipVariableCollectContextList)) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前缺失待验证的加工单信息!");

        //清除本次已获取得到的加工单信息
        productionDispatchContextStepService.removeScanWorkOrderNoContext(reqBean);

        //获取上下文产出零件信息
        List<MesProductionPartContext> cachedProductionPartContextList = productionDispatchContextStepService.getProductionPartContext(reqBean);

        //非扫描场景 清除历史产出零件信息
        if (MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue() != equipVariableCollectContextList.get(0).getMessageSource() && !CollectionUtils.isEmpty(cachedProductionPartContextList)) removeBusiData(reqBean);

        //验证扫描信息是否属于工艺强过码
        Boolean isCraftJumpCode = matchCraftJumpCode(productionProcessContext, equipVariableCollectContextList);

        //验证是否支持强过
        Boolean isAllowJump = checkIsAllowJump(reqBean, cachedProductionPartContextList);

        //不属于工艺强过码,如果此前存在顺序验证失败的数据 则清除此前的产出零件信息
        if (StringUtils.isEmpty(isAllowJump) || (!isCraftJumpCode && isAllowJump)) {
            //删除上下文产出零件信息
            productionDispatchContextStepService.removeProductionPartContext(reqBean);
            cachedProductionPartContextList = null;
        }

        //当前不允许强过
        if (isCraftJumpCode && (StringUtils.isEmpty(isAllowJump) || !isAllowJump))
            return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.SCAN.getValue()).
                    scanInfo(equipVariableCollectContextList.get(0).getEquipVariableValue()), stepResult, String.format("当前扫描信息工艺强过码[%s],当前不支持强过!", equipVariableCollectContextList.get(0).getEquipVariableValue()));

        //允许强过,先更新数据
        if (isCraftJumpCode && !StringUtils.isEmpty(isAllowJump) && isAllowJump) {
            updateProductionPartContextList(reqBean, cachedProductionPartContextList, equipVariableCollectContextList.get(0).getEquipVariableValue());
            return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.SCAN.getValue()).
                    scanInfo(equipVariableCollectContextList.get(0).getEquipVariableValue()), stepResult, String.format("当前扫描信息工艺强过码[%s]!", equipVariableCollectContextList.get(0).getEquipVariableValue()));
        }

        List<MesProductionPartContext> productionPartContextList = new ArrayList<>();

        try {

            //验证工单的有效性
            if (!checkWorkOrderValid(reqBean, resultBean, stepResult, productionProcessContext, equipVariableCollectContextList, productionPartContextList).isCompleted()) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, stepResult.getMsg());

            //扫描场景下合并历史产出零件信息
            if (MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue() == equipVariableCollectContextList.get(0).getMessageSource() && !CollectionUtils.isEmpty(cachedProductionPartContextList)) productionPartContextList.addAll(cachedProductionPartContextList);

            //验证是否全部为空腔
            if (partDataMapSaveStepService.checkIsAllFinishCode(productionPartContextList)) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前加工单信息全部为空腔,已清除当前的空腔数据!");

            //保存零件数据信息
            if (!partDataMapSaveStepService.savePartDataMap2PPC(reqBean, resultBean, stepResult, productionPartContextList, true, true).isCompleted()) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, stepResult.getMsg());

            //保存上下文产出零件信息
            productionDispatchContextStepService.dispatchProductionPartContext(reqBean, productionPartContextList);

            //存储展示组件MODULE_CONTENT内容
            productionDispatchContextStepService.dispatchModuleContentContext(reqBean, getModuleContextData(reqBean, productionPartContextList));

            //当前工位使用的设备
            MesCellEquipContext cellEquipmentContext = productionProcessContext.getCurCellEquip();
            if (MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue() == equipVariableCollectContextList.get(0).getMessageSource() && cellEquipmentContext.getCavity().compareTo(productionPartContextList.size()) > 0)
                return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog().scanInfo(equipVariableCollectContextList.get(0).getEquipVariableValue()),
                        stepResult, false, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT,
                        String.format("当前扫描信息加工单[%s]验证工单状态成功,已知腔数[%s],还需要再连续扫描[%s]次加工单!", equipVariableCollectContextList.get(0).getEquipVariableValue(), cellEquipmentContext.getCavity(), cellEquipmentContext.getCavity() - productionPartContextList.size()));

        } finally {

            //删除手动选择的腔数及工单信息上下文 [结果失败并且非扫描场景]
            if (!stepResult.isCompleted() && MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue() != equipVariableCollectContextList.get(0).getMessageSource()) productionProcessContextStepService.removeFunctionChooseCavityOrderContext(reqBean);

        }

        //保存扫描的工单信息上下文
        if (MesExtEnumUtil.CELL_MESSAGE_SOURCE.READ.getValue() != equipVariableCollectContextList.get(0).getMessageSource()) {
            productionProcessContextStepService.dispatchFunctionChooseCavityOrderContext(reqBean, StationKvBeanUtil.addStationKvBeanList(new ArrayList<>(),
                    new StationKvBean(MesPcnExtConstWords.CAVITY, "腔数", String.valueOf(productionPartContextList.size())),
                    new StationKvBean(MesPcnExtConstWords.CELL_MESSAGE_SOURCE, "工位信息来源", MesExtEnumUtil.CELL_MESSAGE_SOURCE.READ.getValueStr()),
                    new StationKvBean(MesPcnExtConstWords.CRAFT_JUMP_CODE, "是否已验证顺序防错", CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValueStr()),
                    new StationKvBean(MesPcnExtConstWords.WORK_ORDER_NO, "加工单", productionPartContextList.stream().filter(o -> null != o).map(MesProductionPartContext::getWorkOrderNo).collect(Collectors.joining(MesPcnExtConstWords.SEMICOLON)))));
        }

        if (MesExtEnumUtil.CELL_MESSAGE_SOURCE.READ.getValue() == equipVariableCollectContextList.get(0).getMessageSource()) resultBean.setSendBackgroundColor(MesExtEnumUtil.COLOR.UNRESET.getValue());

        String workOrderStr = equipVariableCollectContextList.stream().filter(o -> null != o).map(MesEquipVariableCollectContext::getEquipVariableValue).collect(Collectors.toList()).toString();
        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog().scanInfo(workOrderStr), stepResult, String.format("当前%s加工单%s验证工单状态成功%s!",
                MesExtEnumUtil.CELL_MESSAGE_SOURCE.valueOfDescription(equipVariableCollectContextList.get(0).getMessageSource()), workOrderStr,
                MesExtEnumUtil.CELL_MESSAGE_SOURCE.SCAN.getValue() == equipVariableCollectContextList.get(0).getMessageSource() ? String.format(",当前加工单个数[%s]已满足腔数", productionPartContextList.size()) : MesPcnExtConstWords.EMPTY));

    }

    //验证是否支持强过
    private Boolean checkIsAllowJump(StationRequestBean reqBean, List<MesProductionPartContext> productionPartContextList) {
        Optional<MesProductionPartContext> optional = CollectionUtils.isEmpty(productionPartContextList) ? null : productionPartContextList.stream().filter(o -> (null != o && o.getCheckSeqResult().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0)).findFirst();
        if (null == optional || !optional.isPresent()) return false;
        //非排序是否允许强过, 默认不支持, 不支持返回null, 存在可以跳过的数据且支持跳过返回true
        String isAllowJump = getIsAllowJump(reqBean);
        return StringUtils.isEmpty(isAllowJump) ? null : true;
    }

    //非排序是否允许强过[工位参数]
    private String getIsAllowJump(StationRequestBean reqBean) {
        String isAllowJump = fsmCommonService.handleFsmWcpcMapDataForDoScan(reqBean).get(MesPcnExtConstWords.IS_ALLOW_JUMP);
        return (!StringUtils.isEmpty(isAllowJump) && isAllowJump.equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr())) ? isAllowJump : null;
    }

    //验证扫描信息属于工艺强过码 并且支持强过，进行数据变更
    private void updateProductionPartContextList(StationRequestBean reqBean, List<MesProductionPartContext> productionPartContextList, String craftJumpCode) {
        productionPartContextList.forEach(o -> {
            if (o.getCheckSeqResult().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0) o.setCraftJumpCode(craftJumpCode);
        });
        //保存上下文产出零件信息
        productionDispatchContextStepService.dispatchProductionPartContext(reqBean, productionPartContextList);
    }

    //验证工单的有效性
    private StepResult checkWorkOrderValid(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesProductionProcessContext productionProcessContext,
                                          List<MesEquipVariableCollectContext> equipVariableCollectContextList, List<MesProductionPartContext> productionPartContextList) {

        //从上下文中取出生产线对象
        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();

        //搜集生产工单号
        List<String> filterList = equipVariableCollectContextList.stream().filter(o -> (null != o)).map(MesEquipVariableCollectContext::getEquipVariableValue).collect(Collectors.toList());
        List<String> workOrderNoList = filterList.stream().filter(o -> (!StringUtils.isEmpty(o) && !o.equals(productionProcessContext.getFinishCode()))).distinct().collect(Collectors.toList());

        //获取生产工单信息
        List<MesWorkOrder> workOrderList = workOrderExtService.getWorkOrderList(reqBean.getOrganizeCode(), workOrderNoList);
        Map<String, List<MesWorkOrder>> workOrderMap = CollectionUtils.isEmpty(workOrderList) ? null : workOrderList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesWorkOrder::getWorkOrderNo));

        if (!CollectionUtils.isEmpty(workOrderNoList)) {

            for (String workOrderNo : workOrderNoList) {

                if (StringUtils.isEmpty(workOrderNo)) continue;

                List<MesWorkOrder> workOrderDbList = CollectionUtils.isEmpty(workOrderMap) ? null : workOrderMap.get(workOrderNo);
                if (CollectionUtils.isEmpty(workOrderDbList))
                    return stepResult.isCompleted(false).msg(String.format("请检查工单信息,加工单号[%s]无效!", workOrderNo));

                if (workOrderDbList.size() != 1)
                    return stepResult.isCompleted(false).msg(String.format("请检查生产工单信息,加工单号[%s]存在重复!", workOrderNo));

                if (!MesExtEnumUtil.ORDER_STATUS.checkAllowStatus(workCenter.getCenterType(), workOrderDbList.get(0).getWorkOrderStatus()))
                    return stepResult.isCompleted(false).msg(String.format("请检查工单信息,加工单[%s]信息工单状态[%s]!", workOrderNo, MesExtEnumUtil.ORDER_STATUS.valueOfDescription(workOrderDbList.get(0).getWorkOrderStatus())));

                if (!workOrderDbList.get(0).getWorkCenterCode().equals(reqBean.getWorkCenterCode()))
                    return stepResult.isCompleted(false).msg(String.format("请检查工单信息,加工单[%s]信息所属生产线[%s]与当前生产线[%s]不一致!", workOrderNo, workOrderDbList.get(0).getWorkCenterCode(), reqBean.getWorkCenterCode()));

            }
        }

        //封装产出零件信息
        equipVariableCollectContextList.stream().filter(o -> null != o).forEach(o -> {
            MesProductionPartContext productionPartContext = new MesProductionPartContext()
                    .copyPartNo((!CollectionUtils.isEmpty(workOrderMap) && workOrderMap.containsKey(o.getEquipVariableValue())) ? workOrderMap.get(o.getEquipVariableValue()).get(0) : null, o.getMessageSource())
                    .isCheck(productionProcessContext.getWorkCell());
            if (equipVariableCollectContextList.get(0).getIsConsume().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) productionPartContext.checkSeqResult(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            productionPartContextList.add(productionPartContext);
        });

        return stepResult;

    }

    //封装展示组件MODULE_CONTENT内容
    private List<List<StationKvBean>> getModuleContextData(StationRequestBean reqBean, List<MesProductionPartContext> productionPartContextList) {

        List<List<StationKvBean>> dataList = new ArrayList<>();

        List<MesProductionPartContext> orderList = partDataMapSaveStepService.filterProductionPartContext(productionPartContextList, true);
        List<MesProductionPartContext> finishCodeList = partDataMapSaveStepService.filterProductionPartContext(productionPartContextList, false);

        AtomicReference<Integer> index = new AtomicReference<>(0);

        if (!CollectionUtils.isEmpty(orderList)) {
            orderList.forEach(o -> StationKvBeanUtil.addStationKvBeanList(dataList, new ArrayList<>(),
                    new StationKvBean(MesPcnExtConstWords.WORK_ORDER_NO, "工单号", o.getWorkOrderNo()), new StationKvBean(MesPcnExtConstWords.PART_NO, "零件编码", o.getPartNo()),
                    new StationKvBean(MesPcnExtConstWords.QTY, "完成数/工单数", new StringJoiner(MesPcnExtConstWords.SLANT_R).add(String.valueOf(productionCustomContextStepService.getWorkOrderCompleteQtyContext(reqBean, o).getCompleteQty().intValue())).add(String.valueOf(o.getQty().intValue())).toString()),
                    new StationKvBean(MesPcnExtConstWords.CAVITY, "腔数", new StringJoiner(MesPcnExtConstWords.SLANT_R).add(String.valueOf(index.updateAndGet(v -> v + 1))).add(String.valueOf(productionPartContextList.size())).toString())));
        }

        if (!CollectionUtils.isEmpty(finishCodeList)) {
            StationKvBeanUtil.addStationKvBeanList(dataList, new ArrayList<>(), new StationKvBean(MesPcnExtConstWords.CAVITY_FINISH_CODE, "空腔数", String.valueOf(finishCodeList.size())));
        }

        return dataList;
    }

}
