package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.busi.bu3;

import cn.estsh.i3plus.ext.mes.api.base.bu.IBusiConfigService;
import cn.estsh.i3plus.ext.mes.api.busi.bu3.ISxProdDataPushNotifyStrategyFlagService;
import cn.estsh.i3plus.ext.mes.api.busi.bu3.ISxProdDataPushNotifyStrategyService;
import cn.estsh.i3plus.ext.mes.api.busi.bu3.ISxWorkCenterNotReachReasonService;
import cn.estsh.i3plus.ext.mes.apiservice.util.BusiExtUtil;
import cn.estsh.i3plus.ext.mes.apiservice.util.SxDateRangeUtils;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.SxPushDataNotifyParamAssistModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.model.platform.PushDataNotifyModel;
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.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class SxProdDataPushNotifyStrategyProdRunConditionService implements ISxProdDataPushNotifyStrategyService {

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;

    @Autowired
    private ISxWorkCenterNotReachReasonService workCenterNotReachReasonService;

    @Autowired
    private MesPartExtRepository partExtRepository;

    @Autowired
    private MesShiftProdCenterRecordRepository prodCenterRecordRepository;

    @Autowired
    private MesAssistOutAndEnterRepository assistOutAndEnterRepository;

    @Autowired
    private IBusiConfigService busiConfigService;

    @Autowired
    private MesCareerCorrelationCfgRepository careerCorrelationCfgRepository;

    @Override
    public List<PushDataNotifyModel> exec(PushDataNotifyModel data) {

        log.info("生产数据推送通知数据处理 --- SxProdDataPushNotifyStrategyProdRunConditionService --- START --- DATA:{} --- THREAD:{}", JSONObject.toJSONString(data), Thread.currentThread().getName());
        SxPushDataNotifyParamAssistModel pushParam = analysisParam(data);

        // 达成率 / 完结率
        List<MesWorkCenterNotReachReason> workCenterNotReachReasonsList = new ArrayList<>();

        //获取昨天时间
        String lastDate = SxDateRangeUtils.getDateByNowTime(1);
        //String lastDate = TimeTool.getNowTime(MesExtConstWords.DATE_FORMAT);

        Map<String, MesWorkCenterNotReachReason> workCenterNotReachReasonMapByWorkCenterCode = workCenterNotReachReasonService.getMesWorkCenterNotReachReasonMapByWorkCenterCode(null, lastDate, pushParam.getOrganizeCode());

        Map<String, List<MesWorkOrder>> workOrderMapByWorkCenterCode = workCenterNotReachReasonService.getMesWorkOrderMapByWorkCenterCode(null, lastDate, pushParam.getOrganizeCode());

        Map<String, List<MesOutPutStatistics>> outPutStatisticsMapByWorkCenterCode = workCenterNotReachReasonService.getMesOutPutStatisticsMapByWorkCenterCode(null, lastDate, pushParam.getOrganizeCode());

        List<String> workCenterCodeList = workCenterNotReachReasonService.getWorkCenterCodeList(workOrderMapByWorkCenterCode, outPutStatisticsMapByWorkCenterCode);

        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(pushParam.getOrganizeCode() , MesExtConstWords.OWNER_DEPARTMENT_CFG);

        List<MesWorkCenterExt> ontologyLineWorkCenter = getOntologyLine(pushParam);

        Map<String, MesWorkCenterExt> workCenterExtByCode = ontologyLineWorkCenter.stream().collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, Function.identity(), (x, y) -> y));

        List<String> ontologyLineWorkCenterCodeList = ontologyLineWorkCenter.stream().map(MesWorkCenterExt::getWorkCenterCode).distinct().collect(Collectors.toList());

        // 获取查询作业时间生产的本体线代码
        if (!CollectionUtils.isEmpty(ontologyLineWorkCenterCodeList)) ontologyLineWorkCenterCodeList.retainAll(workCenterCodeList);

        // 综合能率
        Map<String, String> workCenterTotalRateMap = new TreeMap<>();

        // 非作业率
        Map<String, String> unWorkRateMap = new TreeMap<>();

        // 产线援出
        Map<String, Double> assistMapByWorkCenterCode = getAssistMapByWorkCenterCode(pushParam, ownerDepartmentMap, lastDate);

        // 获取停开机记录
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getMesShiftProdCenterRecords(pushParam, lastDate);

        // 勤务时间 根据产线分组
        Map<String, Double> totalServiceTimeMapByWorkCenterCode = getTotalServiceTimeMapByWorkCenterCode(shiftProdCenterRecordList);

        // 非作业时间 根据 产线汇总
        Map<String, Double> totalUnWorkTimeMapByWorkCenterCode = getTotalUnWorkTimeMapByWorkCenterCode(shiftProdCenterRecordList);

        // 产品别生产达成率
        Map<String, String> categoryReachRate = new HashMap<>();

        // 产品别生产达成率
        //Map<String, String> categoryReachRate = new HashMap<>();

        Map<String, MesCareerCorrelationCfg> careerCorrelationCfgMapByWorkCenterCode = getCareerCorrelationCfgMap(lastDate, ontologyLineWorkCenterCodeList);

        // 获取产线生产达成情况
        if (!CollectionUtils.isEmpty(ontologyLineWorkCenterCodeList)) {

            workOrderMapByWorkCenterCode = CollectionUtils.isEmpty(workOrderMapByWorkCenterCode) ? null : workOrderMapByWorkCenterCode.entrySet().stream()
                    .filter(entry -> ontologyLineWorkCenterCodeList.contains(entry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            outPutStatisticsMapByWorkCenterCode = CollectionUtils.isEmpty(outPutStatisticsMapByWorkCenterCode) ? null : outPutStatisticsMapByWorkCenterCode.entrySet().stream()
                    .filter(entry -> ontologyLineWorkCenterCodeList.contains(entry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            // 根据工单和产量统计获取生产的物料
            List<String> partNoList = getPartNoByWorkOrderAndOutPutStatistics(workOrderMapByWorkCenterCode, outPutStatisticsMapByWorkCenterCode);

            // 物料信息
            List<MesPartExt> mesPartExtList = getMesPartExtList(partNoList, pushParam.getOrganizeCode());
            Map<String, MesPartExt> partExtMapByPartNo = mesPartExtList.stream().collect(Collectors.toMap(MesPartExt::getPartNo, Function.identity(), (x, y) -> y));

            //ontologyLineWorkCenterCodeList.stream().distinct()

            for (String workCenterCode : ontologyLineWorkCenterCodeList) {

                workCenterNotReachReasonService.addWorkCenterNotReachReasonList(lastDate, workCenterNotReachReasonsList,
                        workCenterNotReachReasonMapByWorkCenterCode, workOrderMapByWorkCenterCode,
                        outPutStatisticsMapByWorkCenterCode, workCenterCode);

                // 根据物料分组产线统计数据
                Map<String, List<MesOutPutStatistics>> snMapGroupByPartNo = getOutPutStatisticsMap(outPutStatisticsMapByWorkCenterCode, workCenterCode);

                // 综合能率
                workCenterTotalRateMap.put(workCenterCode, getTotalRateDecimalTwo(getStandardWorkTime(partExtMapByPartNo, snMapGroupByPartNo), totalServiceTimeMapByWorkCenterCode.getOrDefault(workCenterCode, 0.0), (CollectionUtils.isEmpty(careerCorrelationCfgMapByWorkCenterCode)) || (!careerCorrelationCfgMapByWorkCenterCode.containsKey(workCenterCode)) ? 0.0 : Double.parseDouble(careerCorrelationCfgMapByWorkCenterCode.get(workCenterCode).getCfgValue2())));

            }

            for (String workCenterCode : totalUnWorkTimeMapByWorkCenterCode.keySet()) {
                // 非作业率
                unWorkRateMap.put(workCenterCode, getRateDecimalTwo(totalUnWorkTimeMapByWorkCenterCode.getOrDefault(workCenterCode, 0.0), totalServiceTimeMapByWorkCenterCode.getOrDefault(workCenterCode, 0.0)) + MesExtConstWords.PERCENT);
            }

            Map<String, List<MesWorkCenterNotReachReason>> workCenterNotReachReasonsMapByCategory = getWorkCenterNotReachReasonsMapByCategory(workCenterNotReachReasonsList, workCenterExtByCode);

            for (Map.Entry<String, List<MesWorkCenterNotReachReason>> workCenterNotReachReasonEntry : workCenterNotReachReasonsMapByCategory.entrySet()) {

                List<MesWorkCenterNotReachReason> workCenterNotReachReasonList = workCenterNotReachReasonEntry.getValue();

                Double completeQty = workCenterNotReachReasonList.stream().mapToDouble(MesWorkCenterNotReachReason::getCompleteQty).sum();
                Double planQty = workCenterNotReachReasonList.stream().mapToDouble(MesWorkCenterNotReachReason::getPlanQty).sum();

                Map<String, Double> completeQtyMapByPartNo = qtyMapByPartNo(workCenterNotReachReasonList, false);

                // 完结率
                //BigDecimal completeRate = BusiExtUtil.divThenMul100Format2RoundHalfUp((double)getCompleteCount(workCenterNotReachReasonList, completeQtyMapByPartNo), (double)completeQtyMapByPartNo.keySet().size());
                // 产品别 ： 完成数量 / 计划数量 达成率 完结率
                categoryReachRate.put(workCenterNotReachReasonEntry.getKey(), completeQty.intValue() + "/" + planQty.intValue() + "&nbsp;&nbsp;" +
                        BusiExtUtil.divThenMul100Format2RoundHalfUp(completeQty, planQty) + MesExtConstWords.PERCENT + "&nbsp;&nbsp;" +
                        BusiExtUtil.divThenMul100Format2RoundHalfUp((double)getCompleteCount(workCenterNotReachReasonList, completeQtyMapByPartNo), (double)completeQtyMapByPartNo.keySet().size()) + MesExtConstWords.PERCENT);
            }

        }

        ISxProdDataPushNotifyStrategyFlagService strategyFlagService = (ISxProdDataPushNotifyStrategyFlagService) SpringContextsUtil.getBean(MesExtEnumUtil.PROD_DATA_PUSH_NOTIFY_STRATEGY_FLAG.flagOfClazz(pushParam.getFlag()));

        log.info("生产数据推送通知数据处理 --- SxProdDataPushNotifyStrategyProdRunConditionService --- END --- THREAD:{}", Thread.currentThread().getName());

        return (List<PushDataNotifyModel>) strategyFlagService.exec(data, pushParam, workCenterNotReachReasonsList, categoryReachRate, workCenterTotalRateMap, totalUnWorkTimeMapByWorkCenterCodeAddMinUnit(doubleValueConvertStringValueMap(totalUnWorkTimeMapByWorkCenterCode), unWorkRateMap), totalAssistMapByWorkCenterCodeAddMinUnit(doubleValueConvertStringValueMap(assistMapByWorkCenterCode)));

    }

    private Map<String, MesCareerCorrelationCfg> getCareerCorrelationCfgMap(String lastDate, List<String> ontologyLineWorkCenterCodeList) {
        List<MesCareerCorrelationCfg> mesCareerCorrelationCfgList = queryCareerCorrelationCfgList(lastDate, ontologyLineWorkCenterCodeList);

        return   CollectionUtils.isEmpty(mesCareerCorrelationCfgList) ? null :mesCareerCorrelationCfgList.stream().filter(o -> o.splitValue() != null).collect(Collectors.toMap(MesCareerCorrelationCfg::getWorkCenterCode, Function.identity(), (x,y) -> y));
    }

    private List<MesCareerCorrelationCfg> queryCareerCorrelationCfgList(String lastDate, List<String> ontologyLineWorkCenterCodeList) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean();
        DdlPreparedPack.getStringEqualPack(MesExtEnumUtil.CAREER_CORRELATION_CFG_DATA_DIMENSION.WORK_CENTER.getValue(), MesExtConstWords.DATA_DIMENSION, packBean);
        DdlPreparedPack.getStringEqualPack(MesExtEnumUtil.CAREER_CORRELATION_CFG_DATA_TYPE.COMPOSITE_RATE_TARGET.getValue(), MesExtConstWords.DATA_TYPE, packBean);
        DdlPreparedPack.getInPackList(ontologyLineWorkCenterCodeList, MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(lastDate.substring(0,4), MesExtConstWords.DATA_KEY, packBean);
        return careerCorrelationCfgRepository.findByHqlWhere(packBean);
    }

    private Map<String, String> totalUnWorkTimeMapByWorkCenterCodeAddMinUnit(Map<String, String> dataMap, Map<String, String> dataMap2){
        if (CollectionUtils.isEmpty(dataMap)) return new HashMap<>();
        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
            entry.setValue(entry.getValue() + "分钟" + "&nbsp;&nbsp;" + dataMap2.get(entry.getKey()));
        }
        return dataMap;
    }

    private Map<String, String> totalAssistMapByWorkCenterCodeAddMinUnit(Map<String, String> dataMap){
        if (CollectionUtils.isEmpty(dataMap)) return new HashMap<>();
        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
            entry.setValue(entry.getValue() + "分钟");
        }
        return dataMap;
    }

    private Map<String, String> doubleValueConvertStringValueMap(Map<String, Double> dataMap){
        if (CollectionUtils.isEmpty(dataMap)) return new HashMap<>();
        return dataMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> String.valueOf(entry.getValue().intValue())));
    }

    private int getCompleteCount(List<MesWorkCenterNotReachReason> workCenterNotReachReasonList, Map<String, Double> completeQtyMapByPartNo){
        Map<String, Double> planQtyMapByPartNo = qtyMapByPartNo(workCenterNotReachReasonList, true);

                /* 完结率=完成个数➗总个数
                   产量➗计划数>=95% 算完成，按物料编码分组。*/
        int completeCount = 0;

        //Map<String, Double> completeQtyMapByPartNo = qtyMapByPartNo(workCenterNotReachReasonList, false);

        for (Map.Entry<String, Double> completeQtyEntry : completeQtyMapByPartNo.entrySet()) {
            if (Double.compare(MathOperation.div(completeQtyEntry.getValue(), planQtyMapByPartNo.get(completeQtyEntry.getKey())), 0.95) >= 0) completeCount++;
        }
        return completeCount;
    }

    private Map<String, Double> qtyMapByPartNo(List<MesWorkCenterNotReachReason> workCenterNotReachReasonList, boolean isGetPlanQtyFlag) {
        return workCenterNotReachReasonList.stream()
                .flatMap(item -> (isGetPlanQtyFlag ? item.getPlanQtyMapByPartNo() : item.getCompleteQtyMapByPartNo()).entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Double::sum));
    }

    private Map<String, List<MesWorkCenterNotReachReason>> getWorkCenterNotReachReasonsMapByCategory(List<MesWorkCenterNotReachReason> workCenterNotReachReasonsList, Map<String, MesWorkCenterExt> workCenterExtByCode) {
        Map<String, List<MesWorkCenterNotReachReason>> workCenterNotReachReasonsListByCategory = new HashMap<>();

        Map<String, List<MesWorkCenterNotReachReason>> workCenterNotReachReasonTempMapByWorkCenterCode = workCenterNotReachReasonsList.stream().collect(Collectors.groupingBy(MesWorkCenterNotReachReason::getWorkCenterCode));

        for (Map.Entry<String, List<MesWorkCenterNotReachReason>> workCenterNotReachReasonByWorkCenterCode : workCenterNotReachReasonTempMapByWorkCenterCode.entrySet()) {

            String categoryCode = workCenterExtByCode.get(workCenterNotReachReasonByWorkCenterCode.getKey()).getCategoryCode();

            workCenterNotReachReasonsListByCategory.put(categoryCode, workCenterNotReachReasonsListByCategory.containsKey(categoryCode) ?
                    addMesWorkCenterNotReachReasonTempList(workCenterNotReachReasonsListByCategory.get(categoryCode), workCenterNotReachReasonByWorkCenterCode.getValue()) :
                    workCenterNotReachReasonByWorkCenterCode.getValue());

        }

        return workCenterNotReachReasonsListByCategory;
    }

    private List<MesWorkCenterNotReachReason> addMesWorkCenterNotReachReasonTempList(List<MesWorkCenterNotReachReason> workCenterNotReachReasonList1, List<MesWorkCenterNotReachReason> workCenterNotReachReasonList2){
        workCenterNotReachReasonList1.addAll(workCenterNotReachReasonList2);
        return workCenterNotReachReasonList1;
    }

    private Map<String, Double> getAssistMapByWorkCenterCode(SxPushDataNotifyParamAssistModel pushParam, Map<String, String> ownerDepartmentMap, String lastDate) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(pushParam.getOrganizeCode());
        //责任部门为 生产技术 责任部门枚举在业务配置中进行维护 配置代码：OWNER_DEPARTMENT_CFG
        //DdlPreparedPack.getStringEqualPack("20", MesExtConstWords.OWNER_DEPARTMENT, packBean);
        DdlPreparedPack.getStringEqualPack(lastDate, MesExtConstWords.INFLUENCE_DATE, packBean);
        List<MesAssistOutAndEnter> assistOutAndEnters = assistOutAndEnterRepository.findByHqlWhere(packBean);

        return assistOutAndEnters.stream().filter(o -> o.getAssistOutAndEnterDetail() != null &&
                o.getAssistOutAndEnterDetail() != MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue()).collect(Collectors.groupingBy(o -> new StringBuilder(o.getWorkCenterCode()).append("（").append(ownerDepartmentMap.containsKey(o.getOwnerDepartment()) ? ownerDepartmentMap.get(o.getOwnerDepartment()) : o.getOwnerDepartment()).append("）").toString(), Collectors.summingDouble(MesAssistOutAndEnter::getInfluenceTime)));
    }

    private Map<String, List<MesOutPutStatistics>> getOutPutStatisticsMap(Map<String, List<MesOutPutStatistics>> outPutStatisticsMapByWorkCenterCode, String workCenterCode) {
        List<MesOutPutStatistics> outPutStatistics = CollectionUtils.isEmpty(outPutStatisticsMapByWorkCenterCode) ? null: outPutStatisticsMapByWorkCenterCode.get(workCenterCode);

        List<MesOutPutStatistics> outPutStatisticsListByShiftCode = CollectionUtils.isEmpty(outPutStatistics) ? new ArrayList<>(0) : outPutStatistics.stream().filter(Objects::nonNull).collect(Collectors.toList());
        return getOutPutStatisticsMapByPartNo(outPutStatisticsListByShiftCode);
    }

    private Map<String, List<MesOutPutStatistics>> getOutPutStatisticsMapByPartNo(List<MesOutPutStatistics> outPutStatisticsMapByWorkCenterCode) {
        return outPutStatisticsMapByWorkCenterCode.stream().collect(Collectors.groupingBy(MesOutPutStatistics::getPartNo));
    }

    private String getTotalRateDecimalTwo(Double d1, Double d2, Double targetRate) {
        double rateDecimalTwo = getRateDecimalTwo(d1, d2);
        return rateDecimalTwo < targetRate ? rateDecimalTwo + MesExtConstWords.PERCENT + "(X)" : rateDecimalTwo + MesExtConstWords.PERCENT + "(O)";
    }

    private double getRateDecimalTwo(Double d1, Double d2) {
        if (StringUtils.isEmpty(d2) || MathOperation.compareTo(d2, 0) == 0) {
            return 0;
        }
        return MathOperation.div(MathOperation.mul(d1, 100), d2, 2);

    }

    private List<MesShiftProdCenterRecord> getMesShiftProdCenterRecords(SxPushDataNotifyParamAssistModel pushParam, String lastDate) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(pushParam.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(lastDate, MesExtConstWords.WORK_TIME, packBean);
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = prodCenterRecordRepository.findByHqlWhere(packBean);
        return shiftProdCenterRecordList;
    }


    public Map<String, Double> getTotalServiceTimeMapByWorkCenterCode(List<MesShiftProdCenterRecord> modelList) {
        List<MesShiftProdCenterRecord> serviceList = modelList.stream().filter(
                o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()
                        || o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()))).collect(Collectors.toList());

        Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordMapByWorkCenter = serviceList.stream().collect(Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode));

        Map<String, Double> totalServiceTimeMapByWorkCenterCode = new TreeMap<>();
        shiftProdCenterRecordMapByWorkCenter.forEach( (workCenterCode, list) -> {
            totalServiceTimeMapByWorkCenterCode.put(workCenterCode, getTotalTimeAmount(list));
        });

        return totalServiceTimeMapByWorkCenterCode;
    }

    public Map<String, Double> getTotalUnWorkTimeMapByWorkCenterCode(List<MesShiftProdCenterRecord> modelList) {
        List<MesShiftProdCenterRecord> serviceList = modelList.stream().filter(
                o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue()
                        || o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());

        Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordMapByWorkCenter = serviceList.stream().collect(Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode));

        Map<String, Double> totalServiceTimeMapByWorkCenterCode = new TreeMap<>();
        shiftProdCenterRecordMapByWorkCenter.forEach( (workCenterCode, list) -> {
            totalServiceTimeMapByWorkCenterCode.put(workCenterCode, getTotalTimeAmount(list));
        });

        return totalServiceTimeMapByWorkCenterCode;
    }

    private Double getTotalTimeAmount(List<MesShiftProdCenterRecord> modelList) {
        return modelList.stream().filter(o -> (null != o &&
                !StringUtils.isEmpty(o.getStartTime()) && !StringUtils.isEmpty(o.getEndTime()) && !StringUtils.isEmpty(o.getWorkerQty()))).
                mapToDouble(o -> MathOperation.mul(getDuration(o.getStartTime(), o.getEndTime()), o.getWorkerQty())).sum();
    }

    private Double getDuration(String startTime, String endTime) {
        try {
            return new Double(TimeTool.getSecoundsBetweenTime(1, startTime, endTime) / 60);
        } catch (Exception e) {
            return new Double(0);
        }
    }

    private List<String> getPartNoByWorkOrderAndOutPutStatistics(Map<String, List<MesWorkOrder>> workOrderMapByWorkCenterCode, Map<String, List<MesOutPutStatistics>> outPutStatisticsMapByWorkCenterCode) {
        List<String> workOrderPartNoList =  CollectionUtils.isEmpty(workOrderMapByWorkCenterCode) ? null : workOrderMapByWorkCenterCode.values()
                .stream()
                .flatMap(List::stream)
                .map(MesWorkOrder::getPartNo)
                .distinct()
                .collect(Collectors.toList());

        List<String> outPutStatisticsPartNoList = CollectionUtils.isEmpty(outPutStatisticsMapByWorkCenterCode) ? null : outPutStatisticsMapByWorkCenterCode.values()
                .stream()
                .flatMap(List::stream)
                .map(MesOutPutStatistics::getPartNo)
                .distinct()
                .collect(Collectors.toList());

        //if (CollectionUtils.isEmpty(workOrderPartNoList)) {
        //    workOrderPartNoList =
        //    workOrderPartNoList.addAll(outPutStatisticsPartNoList);
        //
        //}
        List<String> partNoList;
        if (!CollectionUtils.isEmpty(outPutStatisticsPartNoList) && !CollectionUtils.isEmpty(workOrderPartNoList)) {
            partNoList = Stream.concat(workOrderPartNoList.stream(), outPutStatisticsPartNoList.stream()).filter( o -> !StringUtils.isEmpty(o))
                    .distinct()
                    .collect(Collectors.toList());
        } else if(CollectionUtils.isEmpty(outPutStatisticsPartNoList)){
            partNoList = workOrderPartNoList.stream().distinct().collect(Collectors.toList());
        } else {
            partNoList = outPutStatisticsPartNoList.stream().distinct().collect(Collectors.toList());
        }
        return partNoList;
    }

    private double getStandardWorkTime(Map<String, MesPartExt> partExtMapByPartNo, Map<String, List<MesOutPutStatistics>> snMapGroupByPartNo) {
        double standardWorkTime = 0.0;
        if (CollectionUtils.isEmpty(snMapGroupByPartNo)) return standardWorkTime;
        for (Map.Entry<String, List<MesOutPutStatistics>> snListEntry : snMapGroupByPartNo.entrySet()) {
            //物料标准工数
            Double standardWork = getStandardWorkNum(partExtMapByPartNo, snListEntry);

            //物料的完成数量（各产品当日实绩数量）
            Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

            //产品标准工时
            double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);

            //各产品当日产品标准工时进行累加。
            standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
        }

        return standardWorkTime;
    }

    private Double getStandardWorkNum(Map<String, MesPartExt> partExtMapByPartNo, Map.Entry<String, List<MesOutPutStatistics>> snListEntry) {
        //物料编码
        MesPartExt partExt = partExtMapByPartNo.get(snListEntry.getKey());
        if (partExt == null) {
            log.info("生产数据推送通知数据处理 --- SxProdDataPushNotifyStrategyProdRunConditionService --- 物料编码{}已被删除", snListEntry.getKey());
            return 1.0;
        } else {
            return partExt.getStandardWork() == 0 ? 1 : partExt.getStandardWork();
        }
    }

    private List<MesPartExt> getMesPartExtList(List<String> partNoList, String organizeCode) {
        DdlPackBean partNoPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(partNoList, MesExtConstWords.PART_NO, partNoPackBean);
        //物料信息
        return partExtRepository.findByHqlWhere(partNoPackBean);
    }

    private List<MesWorkCenterExt> getOntologyLine(SxPushDataNotifyParamAssistModel pushParam) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(pushParam.getOrganizeCode());
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.LINE_TYPE.ONTOLOGY_LINE.getValue() + "", MesExtConstWords.LINE_TYPE, packBean);
        return workCenterExtRepository.findByHqlWhere(packBean);
    }

    private SxPushDataNotifyParamAssistModel analysisParam(PushDataNotifyModel data) {

        SxPushDataNotifyParamAssistModel pushParam = JSONObject.parseObject(data.getPushParam(), SxPushDataNotifyParamAssistModel.class);

        if (StringUtils.isEmpty(data.getApiParam())) return restockParamDate(pushParam);

        SxPushDataNotifyParamAssistModel apiParam = JSONObject.parseObject(data.getApiParam(), SxPushDataNotifyParamAssistModel.class);

        return restockParamDate(pushParam.influenceDate(apiParam.getInfluenceDate()));

    }

    private SxPushDataNotifyParamAssistModel restockParamDate(SxPushDataNotifyParamAssistModel pushParam) {
        String curMonth = TimeTool.getToday().substring(0, 7);
        return pushParam.influenceDateStart(append(!StringUtils.isEmpty(pushParam.getInfluenceDate()) ? pushParam.getInfluenceDate() : getMonth(curMonth, -1)))
                .influenceDateEnd(append(!StringUtils.isEmpty(pushParam.getInfluenceDate()) ? getMonth(pushParam.getInfluenceDate(), 1) : curMonth))
                .influenceDate(!StringUtils.isEmpty(pushParam.getInfluenceDate()) ? pushParam.getInfluenceDate() : pushParam.getInfluenceDateStart().substring(0, 7));
    }

    private String append(String influenceDate) { return influenceDate + MesExtConstWords.DATE_DD_01; }

    private String getMonth(String month, int i) { return TimeTool.timeCalc(TimeTool.stringParseToDate(month, MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, i, MesExtConstWords.DATE_FORMAT_YM); }

}
