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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProduceSnExtService;
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.MesEquipVariableCollectContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionProcessContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPsInContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.api.iservice.base.IConfigService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.IStepService;
import cn.estsh.i3plus.pojo.mes.bean.MesConfig;
import cn.estsh.i3plus.pojo.mes.bean.MesProduceSn;
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 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.*;
import java.util.stream.Collectors;

/**
 * @Description : 主条码验证工步
 * @Author : wangjie
 **/
@Slf4j
@Service("mesProductSnCheckStepService")
public class MesProductSnCheckStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private IConfigService configService;

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

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

        if (MesExtEnumUtil.WORK_CENTER_TYPE.SORT.getValue() == workCenter.getCenterType()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "排序线不支持此工步!");

        //获取上下文扫/读信息:主条码
        List<MesEquipVariableCollectContext> equipVariableCollectContextList = productionDispatchContextStepService.getScanProductSnContext(reqBean);

        //没有待验证的主条码, 并且存在已验证过的主条码,默认放行
        if (CollectionUtils.isEmpty(equipVariableCollectContextList) && productionDispatchContextStepService.checkProductionPsInIsExistContext(reqBean))
            return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前没有需要验证的主条码,且存在已验证主条码信息,当前工步默认放行!");

        //没有待验证的主条码
        if (CollectionUtils.isEmpty(equipVariableCollectContextList)) return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前没有需要验证的主条码!");

        //清除本次已获取得到的主条码信息
        productionDispatchContextStepService.removeScanProductSnContext(reqBean);

        //搜集主条码值
        List<String> productSnList = equipVariableCollectContextList.stream().filter(o -> null != o).map(MesEquipVariableCollectContext::getEquipVariableValue).collect(Collectors.toList());

        //获取上下文的工位
        MesWorkCell workCell = productionProcessContext.getWorkCell();

        //验证上下文中主条码的有效性    封装 读/扫主条件信息到进料主条码数据信息中
        List<MesProductionPsInContext> productionPsInContextList = new ArrayList<>();
        if (!checkProduceSnValid(reqBean, resultBean, stepResult, productionProcessContext, workCell, productSnList, equipVariableCollectContextList, productionPsInContextList).isCompleted())
            return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, String.format("验证失败!原因:%s!", stepResult.getMsg()));

        //获取进料主条码数据信息
        List<MesProductionPsInContext> productionPsInContext = productionDispatchContextStepService.getProductionPsInContext(reqBean);
        if (!CollectionUtils.isEmpty(productionPsInContext)) productionPsInContextList.addAll(productionPsInContext);

        //保存进料主条码数据
        productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList);

        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog().scanInfo(productSnList.toString()), stepResult, String.format("主条码%s验证条码状态成功!", productSnList.toString()));

    }

    private List<String> filterEquipVariableCollectContextList(MesProductionProcessContext productionProcessContext, List<MesEquipVariableCollectContext> equipVariableCollectContextList) {
        return equipVariableCollectContextList.stream().filter(o -> (null != o && !o.getEquipVariableValue().equals(productionProcessContext.getFinishCode()))).map(MesEquipVariableCollectContext::getEquipVariableValue).collect(Collectors.toList());
    }

    //获取进料主条码数据信息
    private StepResult checkProduceSnValid(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesProductionProcessContext productionProcessContext, MesWorkCell workCell,
                                           List<String> productSnList, List<MesEquipVariableCollectContext> equipVariableCollectContextList, List<MesProductionPsInContext> productionPsInContextList) {
        //根据零件条码查询零件条码信息
        Map<String, List<MesProduceSn>> produceSnMap = produceSnExtService.getProduceSnMap(reqBean.getOrganizeCode(), productSnList);
        for (MesEquipVariableCollectContext equipVariableCollectContext : equipVariableCollectContextList) {
            if (null == equipVariableCollectContext || StringUtils.isEmpty(equipVariableCollectContext.getEquipVariableValue())) continue;
            if (CollectionUtils.isEmpty(produceSnMap) || !produceSnMap.containsKey(equipVariableCollectContext.getEquipVariableValue()))
                productionPsInContextList.add(new MesProductionPsInContext(reqBean.getOrganizeCode(), equipVariableCollectContext.getEquipVariableValue()).messageSource(equipVariableCollectContext.getMessageSource()));
            else createProductionPsInContext(reqBean, stepResult, workCell, equipVariableCollectContext, produceSnMap.get(equipVariableCollectContext.getEquipVariableValue()), productionPsInContextList);
        }
        return stepResult;
    }

    public StepResult createProductionPsInContext(StationRequestBean reqBean, StepResult stepResult,
                                                  MesWorkCell workCell, MesEquipVariableCollectContext equipVariableCollectContext,
                                                  List<MesProduceSn> produceSnList, List<MesProductionPsInContext> productionPsInContextList) {

        String suffixMsg = !StringUtils.isEmpty(stepResult.getMsg()) ? stepResult.getMsg() + MesPcnExtConstWords.SEMICOLON : MesPcnExtConstWords.EMPTY;

        List<MesProduceSn> unknowList = produceSnList.stream().filter(o -> (null != o && o.getSnStatus().compareTo(MesExtEnumUtil.PRODUCE_SN_STATUS.UNKNOW.getValue()) == 0)).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(unknowList) && unknowList.size() > 1) {
            return stepResult.isCompleted(false).msg(String.format("%s主条码[%s]信息异常,存在[%s]条[未知]状态的记录", suffixMsg, equipVariableCollectContext.getEquipVariableValue(), unknowList.size()));
        }

        if (!CollectionUtils.isEmpty(unknowList) && checkAllowUnknowCenterCfg(reqBean) && (!unknowList.get(0).getWorkCenterCode().equals(reqBean.getWorkCenterCode()) || !unknowList.get(0).getWorkCellCode().equals(reqBean.getWorkCellCode()))) {
            return stepResult.isCompleted(false).msg(String.format("%s主条码[%s]信息条码状态已被%s标记[未知]", suffixMsg, equipVariableCollectContext.getEquipVariableValue(),
                    unknowList.stream().filter(o -> null != o).map(o -> new StringJoiner(MesPcnExtConstWords.AND).add(o.getWorkCenterCode()).add(o.getWorkCellCode()).toString()).collect(Collectors.joining(MesPcnExtConstWords.SEMICOLON))));
        }

        produceSnList = produceSnList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesProduceSn::getCreateDatetime).reversed()).collect(Collectors.toList());

        MesProduceSn produceSn = produceSnList.get(0);

        if (produceSn.getQcStatus().compareTo(MesExtEnumUtil.PRODUCE_QC_STATUS.SUSPICIOUS.getValue()) >= 0)
            return stepResult.isCompleted(false).msg(String.format("%s主条码[%s]质量状态[%s]", suffixMsg, equipVariableCollectContext.getEquipVariableValue(), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSn.getQcStatus())));

        if (produceSn.getSnStatus().compareTo(MesExtEnumUtil.PRODUCE_SN_STATUS.ASSEMBLY_BACK.getValue()) > 0)
            return stepResult.isCompleted(false).msg(String.format("%s主条码[%s]条码状态[%s]", suffixMsg, equipVariableCollectContext.getEquipVariableValue(), MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSn.getSnStatus())));

        //正常条码
        if (produceSn.getSnStatus().compareTo(MesExtEnumUtil.PRODUCE_SN_STATUS.UNKNOW.getValue()) != 0) {

            productionPsInContextList.add(new MesProductionPsInContext(produceSn).isCheck(workCell).messageSource(equipVariableCollectContext.getMessageSource()));

            return stepResult;
        }

        //---- 以下是未知条码的场景判断 ----

        //未知条码, 工序不为空 【代表已完成的工序被重做后未加工完成】
        if (!StringUtils.isEmpty(produceSn.getProcessCode())) {

            productionPsInContextList.add(new MesProductionPsInContext(produceSn).isCheck(workCell).messageSource(equipVariableCollectContext.getMessageSource()).relateId(produceSn.getId()));

            return stepResult;
        }

        //---- 以下是未知条码且工序为空的场景判断 ----

        //未知条码, 工序为空, 条码数量大于1 【新做工序没有加工完成 --> 需要使用上一个条码作为进料条码】
        if (produceSnList.size() > 1) {

            productionPsInContextList.add(new MesProductionPsInContext(produceSnList.get(1)).isCheck(workCell).messageSource(equipVariableCollectContext.getMessageSource()).relateId(produceSn.getId()));

            return stepResult;
        }

        //未知条码, 工序为空, 条码数量等于1, 已打印 【打印件, 首工位自进自出未加工完成】
        if (!StringUtils.isEmpty(produceSn.getPrintStatus()) && produceSn.getPrintStatus().compareTo(MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue()) == 0) {

            productionPsInContextList.add(new MesProductionPsInContext(produceSn).isCheck(workCell).messageSource(equipVariableCollectContext.getMessageSource()).relateId(produceSn.getId()));

            return stepResult;
        }

        //未知条码, 工序为空, 条码数量等于1, 未打印 【外协件作为规则进料生成的条码未加工完成】
        productionPsInContextList.add(new MesProductionPsInContext(reqBean.getOrganizeCode(), equipVariableCollectContext.getEquipVariableValue()).messageSource(equipVariableCollectContext.getMessageSource()).relateId(produceSn.getId()));

        return stepResult;

    }

    //允许扫描其他工位的未知条码的生产线配置, 配置则表示不需要验证未知条码
    private Boolean checkAllowUnknowCenterCfg(StationRequestBean reqBean) {
        List<MesConfig> configList = configService.doCachedConfigList(MesPcnExtConstWords.ALLOW_UNKNOW_CENTER_CFG, reqBean.getOrganizeCode());
        if (CollectionUtils.isEmpty(configList)) return true;
        List<String> allowUnknowCenterList = Arrays.asList(configList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCfgValue()))).map(MesConfig::getCfgValue).collect(Collectors.joining(MesPcnExtConstWords.COMMA)).split(MesPcnExtConstWords.COMMA));
        return (!CollectionUtils.isEmpty(allowUnknowCenterList) && allowUnknowCenterList.contains(reqBean.getWorkCenterCode())) ? false : true;
    }

}
