package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.printqueue.strategy;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesTemplateService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesWorkCenterService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.printqueue.IPrintQueueStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.print.IPrintTemplateStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesProduceSnPrintModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
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.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.repository.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
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.*;
import java.util.stream.Collectors;

/**
 * @PROJECT_NAME: i3plus-mes-yfai
 * @DESCRIPTION:
 * @USER: xinwang.yi
 * @DATE: 2024-09-23 11:08
 */
@Slf4j
@Service
public class WorkOrderAssemblyPrintQueueStrategyService implements IPrintQueueStrategyService {

    @Autowired
    private MesPrintQueueRepository printQueueRepository;

    @Autowired
    private MesWorkOrderRepository workOrderRepository;

    @Autowired
    private MesPartProdGroupRepository partProdGroupRepository;

    @Autowired
    private IMesTemplateService mesTemplateService;

    @Autowired
    private MesCustomerCarModelRepository customerCarModelRepository;

    @Autowired
    private MesWorkOrderAssemblyRepository workOrderAssemblyRepository;

    @Autowired
    private IMesWorkCenterService workCenterService;

    @Autowired
    private IMesPrintedSnLogRepository printedSnLogRepository;

    @Override
    public List<MesPrintQueue> execute(MesPrintQueue model) {

        // 获取需要打印的打印队列
        List<MesPrintQueue> printQueueList = getMesPrintQueues(model);

        List<String> workOrderNoList = CollectionUtils.isEmpty(printQueueList) ? null :
                (printQueueList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkOrderNo()))).map(MesPrintQueue::getWorkOrderNo).collect(Collectors.toList()))
                        .stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        log.info("打印队列查询 --- {} --- 查询到打印数据: {} ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), CollectionUtils.isEmpty(workOrderNoList) ? "[]" : workOrderNoList.toString());

        // 无打印直接返回
        if (CollectionUtils.isEmpty(workOrderNoList)) return null;

        // 获取工单信息
        List<MesWorkOrder> workOrderList = getMesWorkOrders(model, workOrderNoList);
        // 根据工单号对工单分组
        Map<String, List<MesWorkOrder>> workOrderMap = CollectionUtils.isEmpty(workOrderList) ? null : workOrderList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesWorkOrder::getWorkOrderNo));
        if (CollectionUtils.isEmpty(workOrderMap)) log.info("打印队列查询 --- {} --- 工单信息不存在 --- {} ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), workOrderNoList.toString());

        // 产线代码集合
        List<String> workCenterCodeList = CollectionUtils.isEmpty(workOrderMap) ? null :
                (workOrderList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCenterCode()))).map(MesWorkOrder::getWorkCenterCode).collect(Collectors.toList()))
                        .stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        // 根据产线代码节后获取产线信息集合
        List<MesWorkCenter> workCenterList = CollectionUtils.isEmpty(workCenterCodeList) ? null : workCenterService.queryMesWorkCenterList(workCenterCodeList, model.getOrganizeCode());

        // 产线名称集合
        Map<String, List<MesWorkCenter>> workCenterNameMap = CollectionUtils.isEmpty(workCenterList) ? null : workCenterList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesWorkCenter::getWorkCenterCode));

        // 根据零件生产组代码分组
        List<String> partProdGroupCodeList = (printQueueList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartProdGroupCode()))).map(MesPrintQueue::getPartProdGroupCode).collect(Collectors.toList()))
                .stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        Map<String, MesPartProdGroup> partProdGroupMap = CollectionUtils.isEmpty(partProdGroupCodeList) ? null : getMesPartProdGroupMap(model, partProdGroupCodeList);
        if (CollectionUtils.isEmpty(partProdGroupMap)) log.info("打印队列查询 --- {} --- 零件生产组信息不存在 --- {} ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()),
                CollectionUtils.isEmpty(partProdGroupCodeList) ? "[]" : partProdGroupCodeList.toString());

        // 客户车型配置名称MAP
        List<String> carModelCodeList = (workOrderList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCarModelCode()))).map(MesWorkOrder::getCarModelCode).collect(Collectors.toList()))
                .stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        Map<String, MesCustomerCarModel> carModelMapByCode = CollectionUtils.isEmpty(workOrderList) ? null : getMesCustomerCarModelMap(model, carModelCodeList);
        if(CollectionUtils.isEmpty(carModelMapByCode)) log.info("打印队列查询 --- {} --- 客户车型信息 --- {} ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()),
                CollectionUtils.isEmpty(carModelCodeList) ? "[]" : carModelCodeList.toString());

        // 工单装配件
        Map<String, List<MesWorkOrderAssembly>> workOrderAssemblyMapByWorkOrderNo = CollectionUtils.isEmpty(workOrderNoList) ? null : getWorkOrderAssemblyMapByWorkOrderNo(model, workOrderNoList);

        // 展示打印队列列表
        List<MesPrintQueue> showPrintQueueList = new ArrayList<>();

        // 条码打印记录
        List<MesPrintedSnLog> printedSnLogList = new ArrayList<>();

        for (MesPrintQueue printQueue : printQueueList) {

            MesWorkOrder mesWorkOrder = (StringUtils.isEmpty(printQueue.getWorkOrderNo()) || CollectionUtils.isEmpty(workOrderMap) || !workOrderMap.containsKey(printQueue.getWorkOrderNo())) ? null : workOrderMap.get(printQueue.getWorkOrderNo()).get(0);

            if (mesWorkOrder == null) {
                printQueue.setRemark("生产工单不存在");
                printQueue.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.FAILURE.getValue());
                printQueue.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(printQueue, model.getModifyUser());
                log.info("打印队列查询 --- {} --- 工单[{}]不存在 暂不输出打印 ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), printQueue.getWorkOrderNo());
                continue;
            }

            MesPartProdGroup mesPartProdGroup = (StringUtils.isEmpty(printQueue.getPartProdGroupCode()) || CollectionUtils.isEmpty(partProdGroupMap) || !partProdGroupMap.containsKey(printQueue.getPartProdGroupCode())) ? null : partProdGroupMap.get(printQueue.getPartProdGroupCode());
            if (mesPartProdGroup == null || StringUtils.isEmpty(mesPartProdGroup.getPrintTemplate())) {
                printQueue.setRemark("零件生产组信息不存在或模版代码未维护");
                printQueue.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.FAILURE.getValue());
                printQueue.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(printQueue, model.getModifyUser());
                log.info("打印队列查询 --- {} --- 零件生产组[{}]不存在或模版代码未维护 暂不输出打印 ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), printQueue.getPartProdGroupCode());
                continue;
            }

            MesLabelTemplate labelTemplate = mesTemplateService.getLabelTemplate(mesPartProdGroup.getPrintTemplate(), model.getOrganizeCode());
            if (null == labelTemplate || StringUtils.isEmpty(labelTemplate.getMethodCode())) {
                printQueue.setRemark(String.format("模板代码[%s]信息未维护或方法类为空,请配置!", mesPartProdGroup.getPrintTemplate()));
                printQueue.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.FAILURE.getValue());
                printQueue.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(printQueue, model.getModifyUser());
                log.info("打印队列查询 --- {} --- 模板代码[{}]信息未维护或方法类为空,请配置! ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), mesPartProdGroup.getPrintTemplate());
                continue;
            }

            mesWorkOrder.setWorkCenterName((!CollectionUtils.isEmpty(workCenterNameMap) && workCenterNameMap.containsKey(printQueue.getWorkCenterCode())) ? workCenterNameMap.get(printQueue.getWorkCenterCode()).get(0).getWorkCenterName() : "");

            printQueue.setWorkOrderTypeName(MesExtEnumUtil.ORDER_TYPE.valueOfDescription(mesWorkOrder.getWorkOrderType()));

            Map<String, Object> modelMap = new HashMap<>();
            modelMap.put("mesWorkOrder", mesWorkOrder);
            modelMap.put("mesPartProdGroup", mesPartProdGroup);

            MesCustomerCarModel customerCarModel = (CollectionUtils.isEmpty(carModelMapByCode) || !carModelMapByCode.containsKey(mesWorkOrder.getCarModelCode())) ? null : carModelMapByCode.get(mesWorkOrder.getCarModelCode());
            if (customerCarModel != null) {
                modelMap.put("mesCustomerCarModel", customerCarModel);
            }

            if (CollectionUtils.isEmpty(workOrderAssemblyMapByWorkOrderNo) || !workOrderAssemblyMapByWorkOrderNo.containsKey(printQueue.getWorkOrderNo())) {
                printQueue.setRemark("工单装配件清单信息不存在");
                log.info("打印队列查询 --- {} --- 工单[{}]装配件清单信息不存在 ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), printQueue.getWorkOrderNo());
            } else {
                modelMap.put("mesWorkOrderAssemblyList", workOrderAssemblyMapByWorkOrderNo.get(printQueue.getWorkOrderNo()));
            }

            MesProduceSnPrintModel mesProduceSnPrintModel = new MesProduceSnPrintModel();
            mesProduceSnPrintModel.setMesLabelTemplate(labelTemplate);
            mesProduceSnPrintModel.setSourceData(modelMap);
            mesProduceSnPrintModel.setPrinter(mesPartProdGroup.getPrinter());

            MesProduceSnPrintModel snPrintModel;
            try {
                IPrintTemplateStrategyService strategyService = (IPrintTemplateStrategyService) SpringContextsUtil.getBean(labelTemplate.getMethodCode());
                snPrintModel = strategyService.execute(null, mesProduceSnPrintModel, null, null, null ,false);
            } catch (Exception e) {
                log.info("打印队列查询 --- {} --- {} 执行异常! --- {} ---", MesExtEnumUtil.PRINT_QUEUE_TYPE.valueOfDescription(model.getPrintQueueType()), labelTemplate.getMethodCode(), JSONObject.toJSONString(e));
                printQueue.setRemark(String.format("模板代码[%s]方法类[%s]执行异常!", labelTemplate.getTemplateCode(), labelTemplate.getMethodCode()));
                printQueue.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.FAILURE.getValue());
                printQueue.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(printQueue, model.getModifyUser());
                continue;
            }

            printQueue.setPrintTime(TimeTool.getNowTime(true));
            printQueue.setPrintContent(snPrintModel.getPrintContextList());
            printQueue.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue());
            printQueue.setSystemSyncStatus(CommonEnumUtil.FALSE);
            ConvertBean.serviceModelUpdate(printQueue, model.getModifyUser());

            showPrintQueueList.add(printQueue);

            MesPrintedSnLog printedSnLog = new MesPrintedSnLog();
            printedSnLog.setOrganizeCode(printQueue.getOrganizeCode());
            printedSnLog.setWorkOrderNo(printQueue.getWorkOrderNo());
            printedSnLog.setCustPartNo(printQueue.getCustPartNo());
            ConvertBean.serviceModelInitialize(printedSnLog, model.getModifyUser());
            printedSnLogList.add(printedSnLog);

        }

        printQueueRepository.saveAll(printQueueList);

        if (!CollectionUtils.isEmpty(printedSnLogList)) printedSnLogRepository.saveAll(printedSnLogList);

        return showPrintQueueList;
    }

    private Map<String, List<MesWorkOrderAssembly>> getWorkOrderAssemblyMapByWorkOrderNo(MesPrintQueue model, List<String> workOrderNoList) {
        if (CollectionUtils.isEmpty(workOrderNoList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.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<MesWorkOrderAssembly> workOrderAssemblyList = workOrderAssemblyRepository.findByHqlWhere(packBean);
        return CollectionUtils.isEmpty(workOrderAssemblyList) ? null : workOrderAssemblyList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesWorkOrderAssembly::getWorkOrderNo));
    }

    private Map<String, MesCustomerCarModel> getMesCustomerCarModelMap(MesPrintQueue model, List<String> carModelCodeList) {
        if (CollectionUtils.isEmpty(carModelCodeList)) return null;
        // 客户车型配置
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        if (carModelCodeList.size() == 1) DdlPreparedPack.getStringEqualPack(carModelCodeList.get(0), MesPcnExtConstWords.CAR_MODEL_CODE, packBean);
        else DdlPreparedPack.getInPackList(carModelCodeList, MesPcnExtConstWords.CAR_MODEL_CODE, packBean);
        List<MesCustomerCarModel> customerCarModelList = customerCarModelRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(customerCarModelList)) return null;
        customerCarModelList = customerCarModelList.stream().filter(o -> null != o).collect(
                Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesCustomerCarModel::getCarModelCode))), ArrayList::new));
        return customerCarModelList.stream().filter(o -> null != o).collect(Collectors.toMap(MesCustomerCarModel::getCarModelCode, o -> o));
    }

    private Map<String, MesPartProdGroup> getMesPartProdGroupMap(MesPrintQueue model, List<String> partProdGroupCodeList) {
        if (CollectionUtils.isEmpty(partProdGroupCodeList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        if (partProdGroupCodeList.size() == 1) DdlPreparedPack.getStringEqualPack(partProdGroupCodeList.get(0), MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);
        else DdlPreparedPack.getInPackList(partProdGroupCodeList, MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);
        List<MesPartProdGroup> partProdGroupList = partProdGroupRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(partProdGroupList)) return null;
        partProdGroupList = partProdGroupList.stream().filter(o -> null != o).collect(
                Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesPartProdGroup::getPartProdGroupCode))), ArrayList::new));
        return partProdGroupList.stream().filter(o -> null != o).collect(Collectors.toMap(MesPartProdGroup::getPartProdGroupCode, o -> o));
    }

    private List<MesWorkOrder> getMesWorkOrders(MesPrintQueue model, List<String> workOrderNoList) {
        if (CollectionUtils.isEmpty(workOrderNoList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        if (workOrderNoList.size() == 1) DdlPreparedPack.getStringEqualPack(workOrderNoList.get(0), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        else DdlPreparedPack.getInPackList(workOrderNoList, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        return workOrderRepository.findByHqlWhere(packBean);
    }

    private List<MesPrintQueue> getMesPrintQueues(MesPrintQueue model) {

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());

        List<String> workCenterCodeList = Arrays.asList(model.getWorkCenterCodeQuery().split(MesPcnExtConstWords.COMMA));
        List<String> partProdGroupCodeCodeList = Arrays.asList(model.getPartProdGroupCodeQuery().split(MesPcnExtConstWords.COMMA));

        if (workCenterCodeList.size() == 1) DdlPreparedPack.getStringEqualPack(workCenterCodeList.get(0), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        else DdlPreparedPack.getInPackList(workCenterCodeList, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);

        if (workCenterCodeList.size() == 1) DdlPreparedPack.getStringEqualPack(partProdGroupCodeCodeList.get(0), MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);
        else DdlPreparedPack.getInPackList(partProdGroupCodeCodeList, MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);

        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.PRINT_QUEUE_TYPE.PRINT_WORK_ORDER_ASSEMBLY.getValue(), MesPcnExtConstWords.PRINT_QUEUE_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.PRINT_STATUS.UNPRINT.getValue(), MesPcnExtConstWords.PRINT_STATUS, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.ASC.getValue()}, new String[]{MesPcnExtConstWords.CREATE_DATE_TIME}, packBean);
        return printQueueRepository.findByHqlTopWhere(packBean, MesPcnExtConstWords.FOUR);

    }

}
