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.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionAssemblySortContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPartContext;
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.convert.ConvertBean;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
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.MesNumberRuleRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderRepository;
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.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description : 打印客户条码
 * @Reference :
 * @Author : Castle
 * @CreateDate : 2024/6/6 13:39
 * @Modify:
 **/
@Slf4j
@Service
public class MesProductSnPrintSortStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesPrintedSnLogRepository snLogRao;

    @Autowired
    private MesWorkOrderRepository workOrderRepository;

    @Autowired
    private MesNumberRuleRepository numberRuleRepository;

    @Autowired
    private IMesTemplateService mesTemplateService;

    @Autowired
    private IConfigService configService;

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

        //返回打印标识 给前端
        //1. 获取上下文中生成的主条码
        List<MesProductionPartContext> productionPartContextList = productionDispatchContextStepService.getProductionPartContext(reqBean);

        //获取上下文产品加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);

        // 排除掉空腔的partContext数据
        productionPartContextList = CollectionUtils.isEmpty(productionPartContextList) ? null :productionPartContextList.stream().filter(o -> o.getForeignKey() != null).collect(Collectors.toList());

        /**
         * 重构，返回给前端打印数据
         */
        //List<MesProduceSnPrintModel> printModelList = new ArrayList<>();
        //2. 获取条码需要模板、模板代码、打印机 --- 循环遍历条码 封装数据

        if (CollectionUtils.isEmpty(productionPartContextList)) return stepResult;

        // 根据工单号分组
        Map<String, MesWorkOrder> workOrderMap = getMesWorkOrderMap(reqBean, productionPartContextList);

        //加工规则根据数据关联键分组
        Map<Integer, MesProdRuleContext> prodRuleContextMap = prodRuleContextList.stream().filter(o -> null != o).collect(Collectors.toMap(MesProdRuleContext::getForeignKey, o -> o));

        // 获取零件信息上下文
        Map<String, MesPart> partDataContext = productionDispatchContextStepService.getPartDataContext(reqBean);

        //默认客户条码编码规则配置代码
        String defaultCustMatchRule = getDefaultCustMatchRule(reqBean.getOrganizeCode());

        List<MesPrintedSnLog> snLogList = new ArrayList<>();

        List<Map<String, Object>> resultMap = new ArrayList<>();

        for (MesProductionPartContext productionPartContext : productionPartContextList) {

            // 根据工单号获取工单信息
            MesWorkOrder workOrder = workOrderMap.get(productionPartContext.getWorkOrderNo());

            if (null == workOrder) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]信息不存在!", productionPartContext.getWorkOrderNo()));

            if (CollectionUtils.isEmpty(partDataContext) || !partDataContext.containsKey(workOrder.getPartNo()))
                stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]丢失零件信息缓存!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo()));

            MesPart mesPart = partDataContext.get(productionPartContext.getPartNo());

            //验证是否配置客户条码编码规则信息
            String custMatchRule = !StringUtils.isEmpty(mesPart.getCustMatchRule()) ? mesPart.getCustMatchRule() : defaultCustMatchRule;
            if (StringUtils.isEmpty(custMatchRule)) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]未维护客户条码编码规则!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo()));
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
            DdlPreparedPack.getStringEqualPack(custMatchRule, MesPcnExtConstWords.RULE_CODE, packBean);
            MesNumberRule numberRule = numberRuleRepository.getByProperty(packBean);
            if (null == numberRule) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]客户条码编码规则[%s]无效!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo(), custMatchRule));

            //获取零件表的打印模版和打印机
            String labelTemplateCode = mesPart.getCustLabelTemplate();;
            String printer = mesPart.getProductPrinterCode();
            if (StringUtils.isEmpty(labelTemplateCode)) {
                //获取工单装配件的打印模版和打印机
                MesProdRuleContext prodRuleContext = prodRuleContextMap.get(productionPartContext.getForeignKey());
                MesProductionAssemblySortContext productionAssemblySortContext = filterPrintInfo(prodRuleContext);
                labelTemplateCode = null != productionAssemblySortContext ? productionAssemblySortContext.getPrintTemplate() : null;
                printer = null != productionAssemblySortContext ? productionAssemblySortContext.getPrinter() : null;
            }

            if (null == labelTemplateCode) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]未在ERP物料信息维护打印模板,请检查并修改!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo()));

            // 查模板代码
            MesLabelTemplate labelTemplate = mesTemplateService.getLabelTemplate(labelTemplateCode, organizeCode);
            if (null == labelTemplate) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]的模板代码[%s]无效,请检查并修改!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo(), labelTemplateCode));

            MesProduceSnPrintModel mesProduceSnPrintModel = new MesProduceSnPrintModel();
            mesProduceSnPrintModel.setMesLabelTemplate(labelTemplate);
            mesProduceSnPrintModel.setPrinter(printer);
            mesProduceSnPrintModel.setPartNo(productionPartContext.getPartNo());
            mesProduceSnPrintModel.setOrganizeCode(organizeCode);
            mesProduceSnPrintModel.setSourceData(workOrder);
            mesProduceSnPrintModel.setUserName(reqBean.getUserInfo());
            //根据反射获取策略类--封装打印数据
            String methodCode = labelTemplate.getMethodCode();
            //模板信息丢失抛出异常
            if (StringUtils.isEmpty(methodCode)) stepExpSendMsgAndThrowEx(reqBean, resultBean, String.format("工单号[%s]零件号[%s]的模板代码[%s]的反射类丢失,请配置!", productionPartContext.getWorkOrderNo(), productionPartContext.getPartNo(), labelTemplateCode));

            IPrintTemplateStrategyService strategyService = (IPrintTemplateStrategyService) SpringContextsUtil.getBean(methodCode);
            MesProduceSnPrintModel printModel = strategyService.execute(null, mesProduceSnPrintModel, numberRule, stepResult, reqBean, true);
            resultMap.addAll(printModel.getPrintContextList());
            snLogList.add(getMesPrintedSnLog(reqBean, workOrder, JSONObject.toJSONString(printModel.getPrintContextList().iterator().next().get(MesPcnExtConstWords.TEMPLATE_DATA))));
        }

        //前端接收到busiTyep是customComponent，并且 dataType是file类型的消息，就需要打印后续消息里的数据，一个模板对应多个打印数据
        this.sendMessage(reqBean, new StationResultBean()
                .busiType(MesPcnEnumUtil.STATION_BUSI_TYPE.CUSTOM_COMPONENT.getValue())
                .dataType(MesPcnEnumUtil.STATION_DATA_TYPE.FILE.getValue())
                .customPageName(MesPcnExtConstWords.SORT_WORK_CENTER_PRINT)
                .resultObj(resultMap)
        );
        //保存打印条码记录
        snLogRao.saveAll(snLogList);
        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, "打印成功!");
    }

    //默认客户条码编码规则配置代码
    private String getDefaultCustMatchRule(String organizeCode) {
        List<MesConfig> configList = configService.doCachedConfigList(MesPcnExtConstWords.DEFAULT_CUST_MATCH_RULE, organizeCode);
        return !CollectionUtils.isEmpty(configList) ? configList.get(0).getCfgValue() : null;
    }

    private MesPrintedSnLog getMesPrintedSnLog(StationRequestBean reqBean, MesWorkOrder workOrder,String printData) {
        MesPrintedSnLog snLog = new MesPrintedSnLog();
        snLog.setBarcode(workOrder.getCustSn());
        snLog.setCustPartNo(workOrder.getCustPartNo());
        snLog.setWorkOrderNo(workOrder.getWorkOrderNo());
        snLog.setPartNo(workOrder.getPartNo());
        snLog.setPartName(workOrder.getPartName());
        snLog.setPrintData(printData);
        ConvertBean.serviceModelInitialize(snLog, reqBean.getUserInfo());
        snLog.setOrganizeCode(reqBean.getOrganizeCode());
        return snLog;
    }

    private Map<String, MesWorkOrder> getMesWorkOrderMap(StationRequestBean reqBean, List<MesProductionPartContext> productionPartContextList) {
        // 从产成物料上下文中获取 工单号集合
        List<String> workOrderNoList = (productionPartContextList.stream().filter(o ->
                (null != o && !StringUtils.isEmpty(o.getForeignKey()))).map(MesProductionPartContext::getWorkOrderNo).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)
        ).distinct().collect(Collectors.toList());

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(reqBean.getOrganizeCode());
        if (workOrderNoList.size() == 1) DdlPreparedPack.getStringEqualPack(workOrderNoList.get(0), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        else DdlPreparedPack.getInPackList(workOrderNoList, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        List<MesWorkOrder> workOrderList = workOrderRepository.findByHqlWhere(packBean);

        // 根据工单号分组
        return CollectionUtils.isEmpty(workOrderList) ? null :
                workOrderList.stream().collect(Collectors.toMap(o -> o.getWorkOrderNo().toUpperCase(), Function.identity(), (x, y) -> y));
    }

    //过滤打印配置信息
    private MesProductionAssemblySortContext filterPrintInfo(MesProdRuleContext prodRuleContext) {
        List<MesProductionAssemblySortContext> productionAssemblySortContextList = prodRuleContext.getSortAssemblyDataContext();
        Optional<MesProductionAssemblySortContext> optional = CollectionUtils.isEmpty(productionAssemblySortContextList) ? null :
                productionAssemblySortContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPrintTemplate()))).findFirst();
        return (null != optional && optional.isPresent()) ? optional.get() : null;
    }

}
