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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesTemplateService;
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.apiservice.serviceimpl.print.IPrintTemplateStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step.method.MesPartDataMapSaveStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPsOutContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesProduceSnPrintDataModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesProduceSnPrintModel;
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.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
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.repository.IMesPrintedSnLogRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProduceSnRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
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 : 打印主条码 【非排序】
 * @Reference :
 * @Author : Castle
 * @CreateDate : 2024/6/6 13:39
 * @Modify:
 **/
@Service("mesProductSnPrintNosortStepService")
public class MesProductSnPrintNosortStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesTemplateService mesTemplateService;
    @Autowired
    private IMesPrintedSnLogRepository snLogRao;

    @Autowired
    private MesProduceSnRepository mesProduceSnRao;

    @Autowired
    private IConfigService configService;

    @Autowired
    private MesPartDataMapSaveStepService partDataMapSaveStepService;

    @Override
    public StepResult execute(StationRequestBean reqBean) {
//        /**
//         *     Map<String,Object>
//         *         valueList:List<Map<String,Object>>
//         *         paramInfo:{
//         *             templateContent:xxxx,
//         *             labelTemplateParamList: List<Map<String,Object>>
//         *         }
//         *
//         *         根据foreign找出加工规则对应的上下文，判断是否需要打印
//         *
//         */
        String organizeCode = reqBean.getOrganizeCode();
        StationResultBean resultBean = new StationResultBean();
        StepResult stepResult = StepResult.getSuccessComplete();

        //获取上下文加工结果
        String productResult = productionDispatchContextStepService.getProductResultContext(reqBean);
        //验证加工结果是否满足参数条件: 可疑/报废是否打印
        if (checkIsMatchProdResult(reqBean, productResult, MesExtEnumUtil.PRODUCT_RESULT_EQUIP_PARAM.PRODUCT_SUSPICIOUS) || checkIsMatchProdResult(reqBean, productResult, MesExtEnumUtil.PRODUCT_RESULT_EQUIP_PARAM.PRODUCT_SCRAP))
            return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, String.format("打印失败:%s!", MesExtEnumUtil.PRODUCT_RESULT_EQUIP_PARAM.codeOfDescription(productResult)));

        // 根据foreign找出加工规则对应的上下文，判断是否需要打印
        List<MesProdRuleContext> prodRuleDataContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);
        Map<Integer, List<MesProdRuleContext>> prodRuleContextMap = prodRuleDataContextList.stream().collect(Collectors.groupingBy(MesProdRuleContext::getForeignKey));

        //生产过程控制非排序打印机配置【物料级别=1, 默认打印机=2】
        Boolean pcNosortPrinterCfg = getPcNosortPrinterCfg(reqBean.getOrganizeCode());
        //保存零件数据信息
        Map<String, MesPart> partDataMap = savePartDataMap(reqBean, resultBean, stepResult, prodRuleDataContextList, pcNosortPrinterCfg);
        //处理工位零件打印机配置
        List<MesWorkCellPartPrinterCfg> workCellPartPrinterCfgList = productionProcessContextStepService.disPatchWorkCellPartPrinterCfg(reqBean, pcNosortPrinterCfg);

        //需要打印的数据 String 是打印模板code
        Map<String, List<MesProduceSnPrintDataModel>> resultData = new HashMap<>();
        //用于保存客户模板代码 和 模板信息关系
        Map<String, MesLabelTemplate> labelTemplateMap = new HashMap<>();
        //返回打印标识 给前端
        //1. 获取上下文中生成的主条码
        List<MesProductionPsOutContext> productionPsOutContextList = productionDispatchContextStepService.getProductionPsOutContext(reqBean);
        /**
         * 重构，返回给前端打印数据
         */
        List<MesProduceSnPrintModel> printModelList = new ArrayList<>();
        List<Map<String, Object>> resultMapList = new ArrayList<>();
        //2. 获取条码需要模板、模板代码、打印机 --- 循环遍历条码 封装数据
        for (MesProductionPsOutContext sn : productionPsOutContextList) {
            List<MesProdRuleContext> mesProdRuleContexts = prodRuleContextMap.get(sn.getForeignKey());
            if (mesProdRuleContexts == null || mesProdRuleContexts.isEmpty()) {
                stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("零件号[%s]的加工规则丢失,请配置!", sn.getPartNo()));
            }
            MesProdRuleContext mesProdRuleContext = mesProdRuleContexts.get(0);
            Integer isPrint = mesProdRuleContext.getIsPrint();
            if (isPrint == null || isPrint == CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) {
                continue;
            }
            String prodLabelTemplate = sn.getProdLabelTemplate();
            if (prodLabelTemplate == null) {
                stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("零件号[%s]的模板代码[%s]的模板信息丢失,请配置!", sn.getPartNo(), prodLabelTemplate));
            }

            MesProduceSnPrintModel mesProduceSnPrintModel = new MesProduceSnPrintModel();
            // 查模板代码
            MesLabelTemplate labelTemplate = mesTemplateService.getLabelTemplate(prodLabelTemplate, organizeCode);
            mesProduceSnPrintModel.setMesLabelTemplate(labelTemplate);
            mesProduceSnPrintModel.setProductSn(sn.getProductSn());
            mesProduceSnPrintModel.setPartNo(sn.getPartNo());
            mesProduceSnPrintModel.setCustPartNo(sn.getCustPartNo());
            mesProduceSnPrintModel.setOrganizeCode(organizeCode);
            mesProduceSnPrintModel.setUserName(reqBean.getUserInfo());
            if (pcNosortPrinterCfg) {
                //赋值打印机
                String printer = filterPrinter(reqBean, workCellPartPrinterCfgList, partDataMap, sn.getPartNo());
                if (!StringUtils.isEmpty(printer)) mesProduceSnPrintModel.setPrinter(printer);
            }
            List<MesProduceSn> snList = new ArrayList<>();
            snList.add(sn);
            mesProduceSnPrintModel.getMesProduceSnList().addAll(snList);
            //模板信息丢失抛出异常
            if (labelTemplate == null) {
                stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("零件号[%s]的模板代码[%s]的模板信息丢失,请配置!", sn.getPartNo(), prodLabelTemplate));
            }
            //根据反射获取策略类--封装打印数据
            String methodCode = labelTemplate.getMethodCode();
            //模板信息丢失抛出异常
            if (methodCode == null) {
                stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("零件号[%s]的模板代码[%s]的反射类丢失,请配置!", sn.getPartNo(), prodLabelTemplate));
            }
            IPrintTemplateStrategyService strategyService = (IPrintTemplateStrategyService) SpringContextsUtil.getBean(methodCode);
           // GenSerialNoModel model , MesProduceSnPrintModel mesProduceSnPrintModel, MesNumberRule numberRule, StepResult stepResult, StationRequestBean reqBean, Boolean isStep
            MesProduceSnPrintModel printModel = strategyService.execute(null, mesProduceSnPrintModel, null, stepResult, reqBean, true);
            printModelList.add(printModel);
            if (!CollectionUtils.isEmpty(printModel.getPrintContextList()) && printModel.getPrintContextList().size() > MesPcnExtConstWords.ZERO) {
                resultMapList.addAll(printModel.getPrintContextList());
            }
        }

        if (CollectionUtils.isEmpty(printModelList) && CollectionUtils.isEmpty(resultMapList)) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, true,
                    MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, "当前加工规则无需执行打印!");
        }

        //前端接收到busiTyep是customComponent，并且 dataType是file类型的消息，就需要打印后续消息里的数据，一个模板对应多个打印数据
        StationResultBean stationResultBean = new StationResultBean()
                .busiType(MesPcnEnumUtil.STATION_BUSI_TYPE.CUSTOM_COMPONENT.getValue())
                .dataType(MesPcnEnumUtil.STATION_DATA_TYPE.FILE.getValue());
        if (!CollectionUtils.isEmpty(resultMapList) && resultMapList.size() > MesPcnExtConstWords.ZERO) {
            stationResultBean.setCustomPageName(MesPcnExtConstWords.SORT_WORK_CENTER_PRINT);
            stationResultBean.setResultObj(resultMapList);
        } else {
            stationResultBean.setResultObj(printModelList);
        }
        this.sendMessage(reqBean, stationResultBean);
        List<MesPrintedSnLog> snLogList = printModelList.stream().map(MesProduceSnPrintModel::getMesPrintedSnLogList).flatMap(List::stream).collect(Collectors.toList());
        //更新打印状态, 不改同步标志[如果打印在保存加工结果前面会导致未知状态同步到云]
        for (MesProductionPsOutContext outSn : productionPsOutContextList) {
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(outSn.getOrganizeCode());
            DdlPreparedPack.getNumEqualPack(outSn.getId(), MesPcnExtConstWords.ID, packBean);
            mesProduceSnRao.updateByPropertiesNoSync(
                    new String[]{MesPcnExtConstWords.PRINT_STATUS, MesPcnExtConstWords.PRINT_COUNT, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME},
                    new Object[]{MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue(), MesPcnExtConstWords.ONE, reqBean.getUserInfo(), TimeTool.getNowTime(true)},
                    packBean);
        }
        //保存打印条码记录
        snLogRao.saveAll(snLogList);
        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, "打印成功!");
    }

    //获取打印机
    private String filterPrinter(StationRequestBean reqBean, List<MesWorkCellPartPrinterCfg> workCellPartPrinterCfgList, Map<String, MesPart> partDataMap, String partNo) {
        String priter = null;
        if (!CollectionUtils.isEmpty(workCellPartPrinterCfgList)) {
            Optional<MesWorkCellPartPrinterCfg> optional = workCellPartPrinterCfgList.stream().filter(o -> (null != o
                    && !StringUtils.isEmpty(o.getWorkCenterCode()) && o.getWorkCenterCode().toUpperCase().equals(reqBean.getWorkCenterCode().toUpperCase())
                    && !StringUtils.isEmpty(o.getWorkCellCode()) && o.getWorkCellCode().toUpperCase().equals(reqBean.getWorkCellCode().toUpperCase())
                    && !StringUtils.isEmpty(o.getPartNo()) && o.getPartNo().toUpperCase().equals(partNo.toUpperCase()) && !StringUtils.isEmpty(o.getPrinterCode()))).findFirst();
            if (null != optional && optional.isPresent()) priter = optional.get().getPrinterCode();
        }
        if (StringUtils.isEmpty(priter) && !CollectionUtils.isEmpty(partDataMap) && partDataMap.containsKey(partNo)) {
            priter = partDataMap.get(partNo).getProductPrinterCode();
        }
        return priter;
    }

    //保存零件数据信息
    private Map<String, MesPart> savePartDataMap(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<MesProdRuleContext> prodRuleDataContextList, Boolean pcNosortPrinterCfg) {
        if (!pcNosortPrinterCfg) return null;
        //获取上下文零件数据信息
        List<String> partNoList = (prodRuleDataContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getOutPartNo()))).map(MesProdRuleContext::getOutPartNo).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        //保存零件数据信息
        partDataMapSaveStepService.savePartDataMap(reqBean, resultBean, stepResult, partNoList, true, true, false);
        return stepResult.isCompleted() ? (Map<String, MesPart>) stepResult.getObj() : null;
    }

    //生产过程控制非排序打印机配置【物料级别=1, 默认打印机=2】
    private Boolean getPcNosortPrinterCfg(String organizeCode) {
        List<MesConfig> config = configService.doCachedConfigList(MesPcnExtConstWords.PRODUCTION_CONTROL_NOSORT_PRINTER_CFG, organizeCode);
        if (CollectionUtils.isEmpty(config) || StringUtils.isEmpty(config.get(0).getCfgValue())) return false;
        return config.get(0).getCfgValue().equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr()) ? true : false;
    }

    //验证加工结果是否满足参数条件: 可疑/报废是否打印
    private Boolean checkIsMatchProdResult(StationRequestBean reqBean, String productResult, MesExtEnumUtil.PRODUCT_RESULT_EQUIP_PARAM prodResultEnum) {

        if (StringUtils.isEmpty(productResult)) return false;
        if (!productResult.equals(prodResultEnum.getCode())) return false;

        Optional<Map<String, MesProdRouteOptParam>> stepParamMap = getStepParams(reqBean);
        String unPrintParam = (null != stepParamMap && stepParamMap.isPresent() && stepParamMap.get().containsKey(prodResultEnum.name())) ? stepParamMap.get().get(prodResultEnum.name()).getParamValue() : null;
        if (StringUtils.isEmpty(unPrintParam)) return false;

        return true;

    }
}
