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.ISxCategoryCompleteRateService;
import cn.estsh.i3plus.ext.mes.apiservice.dao.IPartExtDao;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.*;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesOutPutStatisticsRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesProdDataToStatisticsOutPutRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesWorkCenterExtRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesWorkOrderExtRepository;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
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.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesPartCategory;
import cn.estsh.i3plus.pojo.mes.repository.MesPartCategoryRepository;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

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

    @Autowired
    private IBusiConfigService busiConfigService;

    @Autowired
    private MesPartCategoryRepository partCategoryRepository;

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private MesProdDataToStatisticsOutPutRepository prodDataToStatisticsOutPutRepository;

    @Autowired
    private MesWorkOrderExtRepository workOrderExtRepository;

    @Autowired
    private IPartExtDao partExtDao;

    @Override
    public SxCategoryCompleteRateModel queryCategoryCompleteRate(SxCategoryCompleteRateModel data) {

        checkParam(data);

        sxYearFlag(data);

        List<MesWorkCenterExt> workCenterExtList = getWorkCenterExtList(data);

        Map<String, MesWorkCenterExt> centerMap = getCenterMap(workCenterExtList);

        Map<String, String> partCategoryCode3Map = partExtDao.queryPartCategoryCode3Map(data.getOrganizeCode(), getCategoryCode3MapByCfg(data.getOrganizeCode()));

        List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList2CurMonth = getOutPutStatisticsList(new SxCategoryCompleteRateModel(data), centerMap, partCategoryCode3Map);

        SxCategoryCompleteRateModel lastYearModel = checkMoreYear(data) ? null : new SxCategoryCompleteRateModel(data).workTimeStart(getLastYear(data.getWorkTimeStart())).workTimeEnd(getLastYear(data.getWorkTimeEnd()));
        List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList2LastYear = null == lastYearModel ? null : getOutPutStatisticsList(lastYearModel, centerMap, partCategoryCode3Map);

        BigDecimal okrTarget = getOkrTarget(data.getOrganizeCode());

        handleChartData(data, outPutStatisticsList2CurMonth, okrTarget);

        handleTableData(data, outPutStatisticsList2LastYear, outPutStatisticsList2CurMonth, okrTarget);

        return data;
    }

    private Boolean checkMoreYear(SxCategoryCompleteRateModel data) {
        if (DIMENSION.YEAR.getCode() == data.getDimension() && !data.getWorkTimeStart().equals(data.getWorkTimeEnd())) return true;
        return false;
    }

    private void checkParam(SxCategoryCompleteRateModel data) {
        if (StringUtils.isEmpty(data.getCategoryCode()) && StringUtils.isEmpty(data.getCareerCode()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("事业别或产品别至少一个必填查询")
                    .build();
        if (!StringUtils.isEmpty(data.getCategoryCode()) && StringUtils.isEmpty(data.getCategoryName()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("查询参数缺失产品别名称[categoryName]")
                    .build();
        if (!StringUtils.isEmpty(data.getCareerCode()) && StringUtils.isEmpty(data.getCareerName()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("查询参数缺失事业别名称[careerName]")
                    .build();
        data.title(!StringUtils.isEmpty(data.getCategoryName()) ? data.getCategoryName() : data.getCareerName());
    }

    private void sxYearFlag(SxEChartsReportCommonDataModel data) {
        MesBusiConfig busiConfig = busiConfigService.getBusiConfigByCfgCode(data.getOrganizeCode(), MesExtConstWords.SX_REPORT_IS_PANASONIC_YEAR);
        if (null != busiConfig) data.setSxYearFlag(true);
    }

    private String getLastYear(String curDate) {
        String year = curDate.substring(0, 4);
        String date = curDate.substring(4);
        return Integer.valueOf(year) - 1 + date;
    }

    private BigDecimal getOkrTarget(String organizeCode) {
        MesBusiConfig busiConfig = busiConfigService.getBusiConfigByCfgCode(organizeCode, MesExtConstWords.SX_REPORT_OKR_CFG);
        try {
            return null == busiConfig || StringUtils.isEmpty(busiConfig.getCfgValue()) ? format2RounHalfUp(new Double(0)) :  divThenMul100Format2RoundHalfUp(new Double(busiConfig.getCfgValue()), new Double(1));
        } catch (NumberFormatException e) {
            return format2RounHalfUp(new Double(0));
        }
    }

    private void handleChartData(SxCategoryCompleteRateModel data, List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList2CurMonth, BigDecimal okrTarget) {
        Map<String, List<SxProdDataToStatisticsOutPutModel>> chartDataMap = CollectionUtils.isEmpty(outPutStatisticsList2CurMonth) ? null :
                outPutStatisticsList2CurMonth.stream().filter(o -> null != o).collect(Collectors.groupingBy(SxProdDataToStatisticsOutPutModel::getGroupInfo));
        List<String> keyList = getKeyList4Date(data);
        for (String key : keyList) {
            List<SxProdDataToStatisticsOutPutModel> chartDataList = CollectionUtils.isEmpty(chartDataMap) ? null : chartDataMap.get(key);
            String itemKey = getItemKey(data.getDimension(), key);
            data.addChartData(itemKey, getCompleteRate(chartDataList), divThenMul100Format2RoundHalfUp(getCompleteQtyAmount(chartDataList), getPlanQtyAmount(chartDataList)), okrTarget);
        }
    }

    private void handleTableData(SxCategoryCompleteRateModel data, List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList2LastYear, List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList2CurMonth, BigDecimal okrTarget) {
        BigDecimal curMonthCompleteRate = getCompleteRate(outPutStatisticsList2CurMonth);
        BigDecimal curMonthReachRate = divThenMul100Format2RoundHalfUp(getCompleteQtyAmount(outPutStatisticsList2CurMonth), getPlanQtyAmount(outPutStatisticsList2CurMonth));
        data.addTableData("1", "完结率",
                getBigDecimalPercent(okrTarget),
                getBigDecimalPercent(getCompleteRate(outPutStatisticsList2LastYear)),
                getBigDecimalPercent(curMonthCompleteRate),
                getCompleteResult(curMonthCompleteRate, okrTarget))
            .addTableData("2","达成率",
                getBigDecimalPercent(okrTarget),
                getBigDecimalPercent(divThenMul100Format2RoundHalfUp(getCompleteQtyAmount(outPutStatisticsList2LastYear), getPlanQtyAmount(outPutStatisticsList2LastYear))),
                getBigDecimalPercent(curMonthReachRate),
                getCompleteResult(curMonthReachRate, okrTarget));
    }

    private String getCompleteResult(BigDecimal curMonthRate, BigDecimal okrTarget) {
        return curMonthRate.compareTo(okrTarget) >= 0 ? CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr() : CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValueStr();
    }

    private BigDecimal getCompleteRate(List<SxProdDataToStatisticsOutPutModel> chartDataList) {
        Map<String, List<SxProdDataToStatisticsOutPutModel>> chartDataMapByPart = CollectionUtils.isEmpty(chartDataList) ? null :
                chartDataList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).collect(Collectors.groupingBy(SxProdDataToStatisticsOutPutModel::getPartNo));
        if (CollectionUtils.isEmpty(chartDataMapByPart)) return format2RounHalfUp(new Double(0));
        Integer count = 0;
        for(Map.Entry<String, List<SxProdDataToStatisticsOutPutModel>> entry : chartDataMapByPart.entrySet()) {
            if (null == entry) continue;
            BigDecimal partCompleteRate = divThenMul100Format2RoundHalfUp(getCompleteQtyAmount(entry.getValue()), getPlanQtyAmount(entry.getValue()));
            if (partCompleteRate.compareTo(format2RounHalfUp(new Double(95))) >= 0) count++;
        }
        return divThenMul100Format2RoundHalfUp(new Double(count), new Double(chartDataMapByPart.size()));
    }

    private Double getCompleteQtyAmount(List<SxProdDataToStatisticsOutPutModel> dataList) {
        return CollectionUtils.isEmpty(dataList) ? new Double(0) :
                dataList.stream().filter(o -> null != o).mapToDouble(SxProdDataToStatisticsOutPutModel::getStatistics).sum();
    }

    private Double getPlanQtyAmount(List<SxProdDataToStatisticsOutPutModel> dataList) {
        return CollectionUtils.isEmpty(dataList) ? new Double(0) :
                dataList.stream().filter(o -> null != o).mapToDouble(SxProdDataToStatisticsOutPutModel::getTotalStatistics).sum();
    }

    private String getItemKey(Integer dimension, String key) {
        switch (DIMENSION.getByCode(dimension)) {
            case YEAR:
                return key;
            case MONTH:
                return Integer.valueOf(key.substring(5, 7)).toString();
            default:
                return Integer.valueOf(key.substring(8, 10)).toString();
        }
    }

    private List<String> getKeyList4Date(SxEChartsReportCommonDataModel data) {
        List<String> keyList = new ArrayList<>();
        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
                String startYear = data.getWorkTimeStart();
                for (int i = 1; i <= 5; i ++) {
                    keyList.add(startYear);
                    startYear = TimeTool.timeCalc(TimeTool.stringParseToDate(startYear, "yyyy"), Calendar.YEAR, 1, "yyyy");
                    if (startYear.compareTo(data.getWorkTimeEnd()) > 0) break;
                }
                break;
            case MONTH:
                String startMonth = DIMENSION.MONTH.getCode() == data.getDimension() ? data.getWorkTimeStart() : (data.getWorkTimeStart() + "-04") ;
                for (int i = 1; i <= 12; i ++) {
                    keyList.add(startMonth);
                    startMonth = TimeTool.timeCalc(TimeTool.stringParseToDate(startMonth, MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, 1, MesExtConstWords.DATE_FORMAT_YM);
                    if (DIMENSION.MONTH.getCode() == data.getDimension() && startMonth.compareTo(data.getWorkTimeEnd()) > 0) break;
                }
                break;
            default:
                String startTime = data.getWorkTimeStart();
                for (int i = 1; i <= 31; i ++) {
                    keyList.add(startTime);
                    startTime = TimeTool.timeCalc(TimeTool.stringParseToDate(startTime, MesExtConstWords.DATE_FORMAT), Calendar.DATE, 1, MesExtConstWords.DATE_FORMAT);
                    if (startTime.compareTo(data.getWorkTimeEnd()) > 0) break;
                }
                break;
        }
        return keyList;
    }

    private List<MesWorkCenterExt> getWorkCenterExtList(SxEChartsReportCommonDataModel data) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(data.getIsDont(), MesExtConstWords.IS_DONT, packBean);
        DdlPreparedPack.getStringEqualPack(data.getDontClass(), MesExtConstWords.DONT_CLASS, packBean);
        return workCenterExtRepository.findByHqlWhere(packBean);
    }

    private Map<String, MesWorkCenterExt> getCenterMap(List<MesWorkCenterExt> workCenterExtList) {
        return CollectionUtils.isEmpty(workCenterExtList) ? null :
                workCenterExtList.stream().filter(o -> null != o).collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, o -> o));
    }

    private Map<String, String> getCategoryCode3Map(String organizeCode) {
        List<MesPartCategory> partCategoryList = partCategoryRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.CATEGORY_TYPE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), MesEnumUtil.PART_CATEGORY_TYPE.CATEGORY_THREE.getValue()});
        partCategoryList = CollectionUtils.isEmpty(partCategoryList) ? partCategoryList :
                partCategoryList.stream().filter(o -> null != o).distinct().collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesPartCategory::getCategoryCode))), ArrayList::new)
                );
        return CollectionUtils.isEmpty(partCategoryList) ? null : partCategoryList.stream().filter(o -> null != o).collect(Collectors.toMap(MesPartCategory::getCategoryCode, MesPartCategory::getCategoryName));
    }

    private Map<String, String> getCategoryCode3MapByCfg(String organizeCode) {
        Map<String, String> categoryCode3Map = getCategoryCode3Map(organizeCode);
        MesBusiConfig cfg = busiConfigService.getBusiConfigByCfgCode(organizeCode, MesExtConstWords.COMPLETE_RATE_CATEGORY3_CFG);
        if (null == cfg || StringUtils.isEmpty(cfg.getCfgValue())) return categoryCode3Map;
        if (CollectionUtils.isEmpty(categoryCode3Map)) categoryCode3Map = new HashMap<>();
        for (String categoryCode3 : cfg.getCfgValue().split(MesExtConstWords.COMMA)) {
            categoryCode3Map.remove(categoryCode3);
        }
        return categoryCode3Map;
    }

    private void calcYmdTime(SxEChartsReportCommonDataModel data) {
        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
                if (!data.getSxYearFlag()) {
                    data.setYmdStart(data.getWorkTimeStart() + MesExtConstWords.DATE_MM_DD_01_01);
                    data.setYmdEnd(data.getWorkTimeStart() + MesExtConstWords.DATE_MM_DD_12_31);
                } else {
                    data.setYmdStart(data.getWorkTimeStart() + MesExtConstWords.DATE_MM_DD_04_01);
                    data.setYmdEnd(Integer.valueOf(data.getWorkTimeEnd()) + 1 + MesExtConstWords.DATE_MM_DD_03_31);
                }
                break;
            case MONTH:
                data.setYmdStart(data.getWorkTimeStart() + MesExtConstWords.DATE_DD_01);
                data.setYmdEnd(getMonthLastDay(data.getWorkTimeEnd()));
                break;
            default:
                data.setYmdStart(data.getWorkTimeStart());
                data.setYmdEnd(data.getWorkTimeEnd());
                break;
        }
    }

    private String getMonthLastDay(String month) {
        return TimeTool.timeCalc(
                TimeTool.stringParseToDate(
                        (TimeTool.timeCalc(TimeTool.stringParseToDate(month, MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, 1, MesExtConstWords.DATE_FORMAT_YM) + MesExtConstWords.DATE_DD_01),
                        MesExtConstWords.DATE_FORMAT),
                Calendar.DATE, -1, MesExtConstWords.DATE_FORMAT);
    }

    private void calcQueryTime(SxEChartsReportCommonDataModel data) {
        String curMonth = TimeTool.getToday().substring(0, 7);
        String curMonthBegin = curMonth + MesExtConstWords.DATE_DD_01;

        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
            case MONTH:
                if (curMonthBegin.compareTo(data.getYmdStart()) <= 0) {
                    data.setWorkTimeYmdStart(data.getYmdStart());
                    data.setWorkTimeYmdEnd(data.getYmdEnd());
                } else if (curMonthBegin.compareTo(data.getYmdEnd()) > 0) {
                    data.setStatisticsYmStart(data.getYmdStart().substring(0, 7));
                    data.setStatisticsYmEnd(data.getYmdEnd().substring(0, 7));
                } else {
                    data.setStatisticsYmStart(data.getYmdStart().substring(0, 7));
                    data.setStatisticsYmEnd(TimeTool.timeCalc(TimeTool.stringParseToDate(curMonth, MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, -1, MesExtConstWords.DATE_FORMAT_YM));
                    data.setWorkTimeYmdStart(curMonthBegin);
                    data.setWorkTimeYmdEnd(data.getYmdEnd());
                }
                break;
            default:
                if (curMonthBegin.compareTo(data.getYmdStart()) <= 0) {
                    data.setWorkTimeYmdStart(data.getYmdStart());
                    data.setWorkTimeYmdEnd(data.getYmdEnd());
                } else if (curMonthBegin.compareTo(data.getYmdEnd()) > 0) {
                    data.setStatisticsYmdStart(data.getYmdStart());
                    data.setStatisticsYmdEnd(data.getYmdEnd());
                } else {
                    data.setStatisticsYmdStart(data.getYmdStart());
                    data.setStatisticsYmdEnd(TimeTool.timeCalc(TimeTool.stringParseToDate(curMonthBegin, MesExtConstWords.DATE_FORMAT), Calendar.DATE, -1, MesExtConstWords.DATE_FORMAT));
                    data.setWorkTimeYmdStart(curMonthBegin);
                    data.setWorkTimeYmdEnd(data.getYmdEnd());
                }
                break;
        }
    }

    private List<SxProdDataToStatisticsOutPutModel> getOutPutStatisticsList(SxCategoryCompleteRateModel data, Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map) {

        calcYmdTime(data);

        calcQueryTime(data);

        List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList = new ArrayList<>();
        if (!StringUtils.isEmpty(data.getWorkTimeYmdStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getOutPutStatisticsRecordList(data, data.getWorkTimeYmdStart(), data.getWorkTimeYmdEnd());
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        if (!StringUtils.isEmpty(data.getStatisticsYmStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getProdDataOutPutStatisticsList(data, data.getStatisticsYmStart(), data.getStatisticsYmEnd());
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        if (!StringUtils.isEmpty(data.getStatisticsYmdStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getProdDataOutPutStatisticsList(data, data.getStatisticsYmdStart(), data.getStatisticsYmdEnd());
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        outPutStatisticsList = CollectionUtils.isEmpty(outPutStatisticsList) ? outPutStatisticsList :
                outPutStatisticsList.stream().filter(o -> (null != o && centerMap.containsKey(o.getWorkCenterCode()))).collect(Collectors.toList());
        outPutStatisticsList = CollectionUtils.isEmpty(outPutStatisticsList) ? outPutStatisticsList :
                outPutStatisticsList.stream().filter(o -> (null != o && partCategoryCode3Map.containsKey(o.getPartNo()))).collect(Collectors.toList());
        return outPutStatisticsList;

    }

    private List<SxProdDataToStatisticsOutPutModel> getOutPutStatisticsRecordList(SxCategoryCompleteRateModel data, String workTimeStart, String workTimeEnd) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(data.getCategoryCode(), MesExtConstWords.CATEGORY_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(data.getCareerCode(), MesExtConstWords.CAREER_CODE, packBean);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesExtConstWords.WORK_ORDER_TYPE, packBean);
        DdlPreparedPack.timeBuilder(workTimeStart, workTimeEnd, MesExtConstWords.WORK_TIME, packBean, false);
        List<MesOutPutStatistics> outPutStatisticsDbList = outPutStatisticsRepository.findByHqlWhere(packBean);

        DdlPackBean packBean1 = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean1);
        DdlPreparedPack.getStringEqualPack(data.getCategoryCode(), "reserved1", packBean1);
        DdlPreparedPack.getStringEqualPack(data.getCareerCode(), "reserved2", packBean1);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesExtConstWords.WORK_ORDER_TYPE, packBean1);
        DdlPreparedPack.timeBuilder(workTimeStart + MesExtConstWords.APPEND_ZERO_HMS, workTimeEnd + MesExtConstWords.APPEND_24_HMS, MesExtConstWords.START_TIME, true, true, packBean1);
        List<MesWorkOrderExt> workOrderExtDbList = workOrderExtRepository.findByHqlWhere(packBean1);

        Map<String, List<MesOutPutStatistics>> outPutDataMap = getOutPutDataMap(data, outPutStatisticsDbList);

        Map<String, List<MesWorkOrderExt>> orderDataMap = getOrderDataMap(data, workOrderExtDbList);

        if (CollectionUtils.isEmpty(outPutDataMap) && CollectionUtils.isEmpty(orderDataMap)) return null;

        List<String> keyList = getKeyList(outPutDataMap, orderDataMap);

        List<SxProdDataToStatisticsOutPutModel> resultList = new ArrayList<>();
        for (String key : keyList) {
            if (StringUtils.isEmpty(key)) continue;
            List<MesOutPutStatistics> outPutStatisticsList = CollectionUtils.isEmpty(outPutDataMap) ? null : outPutDataMap.get(key);
            List<MesWorkOrderExt> workOrderExtList = CollectionUtils.isEmpty(orderDataMap) ? null : orderDataMap.get(key);

            String[] keyArr = key.split(MesExtConstWords.AND);
            SxProdDataToStatisticsOutPutModel statistics = new SxProdDataToStatisticsOutPutModel();
            statistics.setWorkCenterCode(keyArr[0]);
            statistics.setPartNo(keyArr[1]);
            statistics.setWorkOrderType(Integer.valueOf(keyArr[2]));
            statistics.setCategoryCode(keyArr[3]);
            statistics.setCareerCode(keyArr[4]);
            statistics.setQty(getQty(outPutStatisticsList));
            statistics.setRemakeQty(getRemakeQty(outPutStatisticsList));
            calcPlanData(data, statistics, workOrderExtList, outPutStatisticsList);
            statistics.setTotalStatistics(MathOperation.sub(statistics.getPlanQty(), statistics.getPlanRemakeQty()));
            statistics.setStatistics(MathOperation.sub(statistics.getQty(), statistics.getRemakeQty()));
            statistics.setOrganizeCode(data.getOrganizeCode());
            statistics.setWorkTime(keyArr[5]);
            statistics.setGroupInfo(getGroupInfo(data, statistics.getWorkTime()));
            resultList.add(statistics);

        }

        return resultList;
    }

    private void calcPlanData(SxEChartsReportCommonDataModel data, SxProdDataToStatisticsOutPutModel statistics, List<MesWorkOrderExt> workOrderExtList, List<MesOutPutStatistics> outPutStatisticsList) {
        Double planQty = new Double(0);
        Double planRemakeQty = new Double(0);
        Map<String, List<MesOutPutStatistics>> outPutMap = CollectionUtils.isEmpty(outPutStatisticsList) ? null :
                outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesOutPutStatistics::getWorkOrderNo));
        Map<String, MesWorkOrderExt> orderMap = CollectionUtils.isEmpty(workOrderExtList) ? null :
                workOrderExtList.stream().filter(o -> null != o).collect(Collectors.toMap(MesWorkOrderExt::getOrderNo, o -> o));
        List<String> orderNoList = getOrderNoList(orderMap, outPutMap);

        for (String orderNo : orderNoList) {
            if (StringUtils.isEmpty(orderNo)) continue;
            MesWorkOrderExt workOrderExt = CollectionUtils.isEmpty(orderMap) ? null : orderMap.get(orderNo);
            List<MesOutPutStatistics> outPutStatisticListByOrder = CollectionUtils.isEmpty(outPutMap) ? null : outPutMap.get(orderNo);

            if (null != workOrderExt && CollectionUtils.isEmpty(outPutStatisticListByOrder)) {
                planQty = MathOperation.add(planQty, workOrderExt.getQty());
                planRemakeQty = MathOperation.add(planRemakeQty, workOrderExt.getPlanQty());
            } else if (null == workOrderExt && !CollectionUtils.isEmpty(outPutStatisticListByOrder)) {
                for (MesOutPutStatistics item : outPutStatisticListByOrder) {
                    if (null == item) continue;
                    if (getOutPutFlag(item.getOutPutFlag())) {
                        planQty = MathOperation.add(planQty, item.getQty());
                        planRemakeQty = MathOperation.add(planRemakeQty, item.getRemakeQty());
                    }
                }
            } else {
                List<MesOutPutStatistics> itemList1 = outPutStatisticListByOrder.stream().filter(o -> (null != o && (!StringUtils.isEmpty(o.getOutPutFlag()) && CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(o.getOutPutFlag())))).collect(Collectors.toList());
                List<MesOutPutStatistics> itemList2 = outPutStatisticListByOrder.stream().filter(o -> (null != o && (StringUtils.isEmpty(o.getOutPutFlag()) || CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValueStr().equals(o.getOutPutFlag())))).collect(Collectors.toList());
                List<MesOutPutStatistics> itemList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(itemList1)) itemList.addAll(itemList1);
                if (!CollectionUtils.isEmpty(itemList2)) itemList.add(itemList2.get(0));

                for (MesOutPutStatistics item : itemList) {
                    if (null == item) continue;
                    if (getGroupInfo2(data, workOrderExt.getStartTime()).equals(getGroupInfo2(data, item.getWorkTime()))) {
                        if (getOutPutFlag(item.getOutPutFlag())) {
                            planQty = MathOperation.add(planQty, item.getQty());
                            planRemakeQty = MathOperation.add(planRemakeQty, item.getRemakeQty());
                        } else {
                            planQty = MathOperation.add(planQty, workOrderExt.getQty());
                            planRemakeQty = MathOperation.add(planRemakeQty, workOrderExt.getPlanQty());
                        }
                    } else {
                        if (getOutPutFlag(item.getOutPutFlag())) {
                            planQty = MathOperation.add(planQty, item.getQty());
                            planRemakeQty = MathOperation.add(planRemakeQty, item.getRemakeQty());
                        }
                    }
                }
            }
        }
        statistics.setPlanQty(planQty);
        statistics.setPlanRemakeQty(planRemakeQty);
    }

    private List<String> getOrderNoList(Map<String, MesWorkOrderExt> orderMap, Map<String, List<MesOutPutStatistics>> outPutMap) {
        List<String> orderNoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderMap)) orderNoList.addAll(new ArrayList<>(orderMap.keySet()));
        if (!CollectionUtils.isEmpty(outPutMap)) orderNoList.addAll(new ArrayList<>(outPutMap.keySet()));
        orderNoList = CollectionUtils.isEmpty(orderNoList) ? null : orderNoList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        return orderNoList;
    }

    private Boolean getOutPutFlag(String outPutFlag) {
        return !StringUtils.isEmpty(outPutFlag) && CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(outPutFlag);
    }

    private List<SxProdDataToStatisticsOutPutModel> getProdDataOutPutStatisticsList(SxCategoryCompleteRateModel data, String workTimeStart, String workTimeEnd) {
        DdlPackBean packBean = getOutPutStatisticsPackBeanByType(data, workTimeStart, workTimeEnd);
        List<MesProdDataToStatisticsOutPut> prodDataToStatisticsOutPutList = prodDataToStatisticsOutPutRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(prodDataToStatisticsOutPutList)) return null;
        List<SxProdDataToStatisticsOutPutModel> resultList = new ArrayList<>();
        for (MesProdDataToStatisticsOutPut item : prodDataToStatisticsOutPutList) {
            if (null == item) continue;
            SxProdDataToStatisticsOutPutModel result = new SxProdDataToStatisticsOutPutModel();
            BeanUtils.copyProperties(item, result);
            result.setGroupInfo(getGroupInfo(data, result.getWorkTime()));
            resultList.add(result);
        }
        return resultList;
    }

    private String getGroupInfo(SxEChartsReportCommonDataModel data, String workTime) {
        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
                String year = workTime.substring(0, 4);
                if (!data.getSxYearFlag()) return year;
                else {
                    workTime = workTime.length() == 7 ? workTime + MesExtConstWords.DATE_DD_01 : workTime;
                    if (workTime.compareTo(year + MesExtConstWords.DATE_MM_DD_04_01) >= 0) return year;
                    else return String.valueOf(Integer.parseInt(year) - 1);
                }
            case MONTH:
                return workTime.substring(0, 7);
            default:
                return workTime.substring(0, 10);
        }
    }

    private String getGroupInfo2(SxEChartsReportCommonDataModel data, String workTime) {
        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
            case MONTH:
                return workTime.substring(0, 7);
            default:
                return workTime.substring(0, 10);
        }
    }

    private DdlPackBean getOutPutStatisticsPackBeanByType(SxEChartsReportCommonDataModel data, String workTimeStart, String workTimeEnd) {
        DdlPackBean packBean = getStatisticsPackBeanByType(data, workTimeStart, workTimeEnd);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesExtConstWords.WORK_ORDER_TYPE, packBean);
        if (workTimeStart.length() <= 7) {
            DdlPreparedPack.getStringEqualPack(MesExtConstWords.MONTH, MesExtConstWords.DATA_TYPE, packBean);
            DdlPreparedPack.getStringEqualPack(MesExtEnumUtil.JOB_STATISTICS_PROD_DATA_KEY.OUT_PUT_MONTH_KEY2.getValue(), MesExtConstWords.DATA_KEY, packBean);
        } else {
            DdlPreparedPack.getStringEqualPack(MesExtConstWords.DAY, MesExtConstWords.DATA_TYPE, packBean);
            DdlPreparedPack.getStringEqualPack(MesExtEnumUtil.JOB_STATISTICS_PROD_DATA_KEY.OUT_PUT_DAY_KEY2.getValue(), MesExtConstWords.DATA_KEY, packBean);
        }
        return packBean;
    }

    private DdlPackBean getStatisticsPackBeanByType(SxEChartsReportCommonDataModel data, String workTimeStart, String workTimeEnd) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getCategoryCode(), MesExtConstWords.CATEGORY_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(data.getCareerCode(), MesExtConstWords.CAREER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.timeBuilder(workTimeStart, workTimeEnd, MesExtConstWords.WORK_TIME, packBean, false);
        return packBean;
    }

    private Map<String, List<MesOutPutStatistics>> getOutPutDataMap(SxEChartsReportCommonDataModel data, List<MesOutPutStatistics> outPutStatisticsList) {
        return CollectionUtils.isEmpty(outPutStatisticsList) ? null :
                outPutStatisticsList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCareerCode()) && !StringUtils.isEmpty(o.getCategoryCode()))).collect(Collectors.groupingBy(o ->
                        new StringJoiner(MesExtConstWords.AND).add(o.getWorkCenterCode()).add(o.getPartNo()).add(o.getWorkOrderType().toString()).add(o.getCategoryCode()).add(o.getCareerCode()).add(getGroupInfo(data, o.getWorkTime())).toString()));
    }

    private Map<String, List<MesWorkOrderExt>> getOrderDataMap(SxEChartsReportCommonDataModel data, List<MesWorkOrderExt> workOrderExtList) {
        return CollectionUtils.isEmpty(workOrderExtList) ? null :
                workOrderExtList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getReserved1()) && !StringUtils.isEmpty(o.getReserved2()) &&
                        MesExtEnumUtil.WORK_ORDER_STATUS.CREATE.getValue() != o.getWorkOrderStatus() && MesExtEnumUtil.WORK_ORDER_STATUS.REMOVE.getValue() != o.getWorkOrderStatus())
                ).collect(Collectors.groupingBy(o -> new StringJoiner(MesExtConstWords.AND).add(o.getWorkCenterCode()).add(o.getPartNo()).add(o.getWorkOrderType().toString()).add(o.getReserved1()).add(o.getReserved2()).add(getGroupInfo(data, o.getStartTime())).toString()));
    }

    public List<String> getKeyList(Map<String, List<MesOutPutStatistics>> outPutDataMap, Map<String, List<MesWorkOrderExt>> orderDataMap) {
        List<String> keyList = null;
        if (!CollectionUtils.isEmpty(outPutDataMap) || !CollectionUtils.isEmpty(orderDataMap)) keyList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(outPutDataMap)) keyList.addAll(new ArrayList<>(outPutDataMap.keySet()));
        if (!CollectionUtils.isEmpty(orderDataMap)) keyList.addAll(new ArrayList<>(orderDataMap.keySet()));
        keyList = CollectionUtils.isEmpty(keyList) ? null : keyList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        return keyList;
    }

    public Double getQty(List<MesOutPutStatistics> itemList) {
        return CollectionUtils.isEmpty(itemList) ? new Double(0) : itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getQty()))).mapToDouble(MesOutPutStatistics::getQty).sum();
    }

    private Double getRemakeQty(List<MesOutPutStatistics> itemList) {
        return CollectionUtils.isEmpty(itemList) ? new Double(0) : itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getRemakeQty()))).mapToDouble(MesOutPutStatistics::getRemakeQty).sum();
    }

    private String getBigDecimalPercent(BigDecimal b) {
        return b + MesExtConstWords.PERCENT;
    }

    private BigDecimal divThenMul100Format2RoundHalfUp(Double d1, Double d2) {
        Double d = (MathOperation.compareTo(d1, new Double(0)) == 0 || MathOperation.compareTo(d2, new Double(0)) == 0)
                ? null : MathOperation.mul(MathOperation.div(d1, d2), new Double(100));
        return format2RounHalfUp(d);
    }

    private BigDecimal format2RounHalfUp(Double d) {
        if (StringUtils.isEmpty(d)) d = new Double(0);
        BigDecimal bd = new BigDecimal(d);
        bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
        return bd;
    }

    @Override
    public SxCompleteRateChartModel queryCompleteRateChart(SxCompleteRateChartModel data) {

        sxYearFlag(data);

        calcYmdTime(data);

        calcQueryTime(data);

        List<MesWorkCenterExt> workCenterExtList = getWorkCenterExtList(data);

        Map<String, MesWorkCenterExt> centerMap = getCenterMap(workCenterExtList);

        Map<String, String> partCategoryCode3Map = partExtDao.queryPartCategoryCode3Map(data.getOrganizeCode(), data.getCategoryCode3());

        Map<String, String> categoryCode3Map = getCategoryCode3Map(data.getOrganizeCode());

        List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList = getOutPutStatisticsList(data, centerMap, partCategoryCode3Map);

        Map<String, List<SxProdDataToStatisticsOutPutModel>> listMap = getOutPutDataMapByDataDimension(data, outPutStatisticsList);

        handleTableNameList(data);

        handleTableDataList(data, categoryCode3Map, centerMap, listMap);

        return data;
    }

    private List<SxProdDataToStatisticsOutPutModel> getOutPutStatisticsList(SxCompleteRateChartModel data, Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map) {

        List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList = new ArrayList<>();
        if (!StringUtils.isEmpty(data.getWorkTimeYmdStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getOutPutStatisticsRecordList(data, data.getWorkTimeYmdStart(), data.getWorkTimeYmdEnd(), centerMap, partCategoryCode3Map);
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        if (!StringUtils.isEmpty(data.getStatisticsYmStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getProdDataOutPutStatisticsList(data, data.getStatisticsYmStart(), data.getStatisticsYmEnd(), centerMap, partCategoryCode3Map);
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        if (!StringUtils.isEmpty(data.getStatisticsYmdStart())) {
            List<SxProdDataToStatisticsOutPutModel> resultList = getProdDataOutPutStatisticsList(data, data.getStatisticsYmdStart(), data.getStatisticsYmdEnd(), centerMap, partCategoryCode3Map);
            if (!CollectionUtils.isEmpty(resultList)) outPutStatisticsList.addAll(resultList);
        }
        return outPutStatisticsList;

    }

    private List<SxProdDataToStatisticsOutPutModel> getOutPutStatisticsRecordList(SxCompleteRateChartModel data, String workTimeStart, String workTimeEnd,
                                                                                  Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesExtConstWords.WORK_ORDER_TYPE, packBean);
        DdlPreparedPack.timeBuilder(workTimeStart, workTimeEnd, MesExtConstWords.WORK_TIME, packBean, false);
        List<MesOutPutStatistics> outPutStatisticsDbList = outPutStatisticsRepository.findByHqlWhere(packBean);
        outPutStatisticsDbList = filterOutPutStatisticsDbList(outPutStatisticsDbList, centerMap, partCategoryCode3Map, data.getCategoryCode3());

        DdlPackBean packBean1 = DdlPackBean.getDdlPackBean(data.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(data.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean1);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesExtConstWords.WORK_ORDER_TYPE, packBean1);
        DdlPreparedPack.timeBuilder(workTimeStart + MesExtConstWords.APPEND_ZERO_HMS, workTimeEnd + MesExtConstWords.APPEND_24_HMS, MesExtConstWords.START_TIME, true, true, packBean1);
        List<MesWorkOrderExt> workOrderExtDbList = workOrderExtRepository.findByHqlWhere(packBean1);
        workOrderExtDbList = filterWorkOrderExtDbList(workOrderExtDbList, centerMap, partCategoryCode3Map, data.getCategoryCode3());

        Map<String, List<MesOutPutStatistics>> outPutDataMap = getOutPutDataMap(data, outPutStatisticsDbList);

        Map<String, List<MesWorkOrderExt>> orderDataMap = getOrderDataMap(data, workOrderExtDbList);

        if (CollectionUtils.isEmpty(outPutDataMap) && CollectionUtils.isEmpty(orderDataMap)) return null;

        List<String> keyList = getKeyList(outPutDataMap, orderDataMap);

        List<SxProdDataToStatisticsOutPutModel> resultList = new ArrayList<>();
        for (String key : keyList) {
            if (StringUtils.isEmpty(key)) continue;
            List<MesOutPutStatistics> outPutStatisticsList = CollectionUtils.isEmpty(outPutDataMap) ? null : outPutDataMap.get(key);
            List<MesWorkOrderExt> workOrderExtList = CollectionUtils.isEmpty(orderDataMap) ? null : orderDataMap.get(key);

            String[] keyArr = key.split(MesExtConstWords.AND);
            SxProdDataToStatisticsOutPutModel statistics = new SxProdDataToStatisticsOutPutModel();
            statistics.setWorkCenterCode(keyArr[0]);
            statistics.setIsDont(centerMap.get(statistics.getWorkCenterCode()).getIsDont());
            statistics.setDontClass(centerMap.get(statistics.getWorkCenterCode()).getDontClass());
            statistics.setPartNo(keyArr[1]);
            statistics.setWorkOrderType(Integer.valueOf(keyArr[2]));
            statistics.setCategoryCode(keyArr[3]);
            statistics.setCareerCode(keyArr[4]);
            statistics.setQty(getQty(outPutStatisticsList));
            statistics.setRemakeQty(getRemakeQty(outPutStatisticsList));
            calcPlanData(data, statistics, workOrderExtList, outPutStatisticsList);
            statistics.setTotalStatistics(MathOperation.sub(statistics.getPlanQty(), statistics.getPlanRemakeQty()));
            statistics.setStatistics(MathOperation.sub(statistics.getQty(), statistics.getRemakeQty()));
            statistics.setOrganizeCode(data.getOrganizeCode());
            statistics.setWorkTime(keyArr[5]);
            statistics.setGroupInfo(getGroupInfo3(data, statistics.getWorkTime()));
            statistics.setCategoryCode3((!CollectionUtils.isEmpty(partCategoryCode3Map) && partCategoryCode3Map.containsKey(statistics.getPartNo())) ? partCategoryCode3Map.get(statistics.getPartNo()) : MesExtConstWords.EMPTY);
            resultList.add(statistics);
        }
        return resultList;
    }

    private List<SxProdDataToStatisticsOutPutModel> getProdDataOutPutStatisticsList(SxCompleteRateChartModel data, String workTimeStart, String workTimeEnd,
                                                                                    Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map) {
        DdlPackBean packBean = getOutPutStatisticsPackBeanByType(data, workTimeStart, workTimeEnd);
        List<MesProdDataToStatisticsOutPut> prodDataToStatisticsOutPutList = prodDataToStatisticsOutPutRepository.findByHqlWhere(packBean);
        prodDataToStatisticsOutPutList = filterProdDataToStatisticsOutPutList(prodDataToStatisticsOutPutList, centerMap, partCategoryCode3Map, data.getCategoryCode3());
        if (CollectionUtils.isEmpty(prodDataToStatisticsOutPutList)) return null;
        List<SxProdDataToStatisticsOutPutModel> resultList = new ArrayList<>();
        for (MesProdDataToStatisticsOutPut item : prodDataToStatisticsOutPutList) {
            if (null == item) continue;
            SxProdDataToStatisticsOutPutModel statistics = new SxProdDataToStatisticsOutPutModel();
            BeanUtils.copyProperties(item, statistics);
            statistics.setIsDont(centerMap.get(statistics.getWorkCenterCode()).getIsDont());
            statistics.setDontClass(centerMap.get(statistics.getWorkCenterCode()).getDontClass());
            statistics.setGroupInfo(getGroupInfo3(data, statistics.getWorkTime()));
            statistics.setCategoryCode3((!CollectionUtils.isEmpty(partCategoryCode3Map) && partCategoryCode3Map.containsKey(statistics.getPartNo())) ? partCategoryCode3Map.get(statistics.getPartNo()) : MesExtConstWords.EMPTY);
            resultList.add(statistics);
        }
        return resultList;
    }

    private List<MesOutPutStatistics> filterOutPutStatisticsDbList(List<MesOutPutStatistics> outPutStatisticsDbList, Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map, String categoryCode3) {
        outPutStatisticsDbList = CollectionUtils.isEmpty(outPutStatisticsDbList) ? null :
                outPutStatisticsDbList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCareerCode()) && !StringUtils.isEmpty(o.getCategoryCode()) && centerMap.containsKey(o.getWorkCenterCode()))).collect(Collectors.toList());
        if (!StringUtils.isEmpty(categoryCode3))
            outPutStatisticsDbList = (CollectionUtils.isEmpty(outPutStatisticsDbList) || CollectionUtils.isEmpty(partCategoryCode3Map)) ? null : outPutStatisticsDbList.stream().filter(o -> (null != o && partCategoryCode3Map.containsKey(o.getPartNo()))).collect(Collectors.toList());
        return outPutStatisticsDbList;
    }

    private List<MesWorkOrderExt> filterWorkOrderExtDbList(List<MesWorkOrderExt> workOrderExtDbList, Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map, String categoryCode3) {
        workOrderExtDbList = CollectionUtils.isEmpty(workOrderExtDbList) ? null :
                workOrderExtDbList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getReserved1()) && !StringUtils.isEmpty(o.getReserved2()) && centerMap.containsKey(o.getWorkCenterCode()) &&
                        MesExtEnumUtil.WORK_ORDER_STATUS.CREATE.getValue() != o.getWorkOrderStatus() && MesExtEnumUtil.WORK_ORDER_STATUS.REMOVE.getValue() != o.getWorkOrderStatus())).collect(Collectors.toList());
        if (!StringUtils.isEmpty(categoryCode3))
            workOrderExtDbList = (CollectionUtils.isEmpty(workOrderExtDbList) || CollectionUtils.isEmpty(partCategoryCode3Map)) ? null : workOrderExtDbList.stream().filter(o -> (null != o && partCategoryCode3Map.containsKey(o.getPartNo()))).collect(Collectors.toList());
        return workOrderExtDbList;
    }

    private List<MesProdDataToStatisticsOutPut> filterProdDataToStatisticsOutPutList(List<MesProdDataToStatisticsOutPut> prodDataToStatisticsOutPutList, Map<String, MesWorkCenterExt> centerMap, Map<String, String> partCategoryCode3Map, String categoryCode3) {
        prodDataToStatisticsOutPutList = CollectionUtils.isEmpty(prodDataToStatisticsOutPutList) ? null :
                prodDataToStatisticsOutPutList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCareerCode()) && !StringUtils.isEmpty(o.getCategoryCode()) && centerMap.containsKey(o.getWorkCenterCode()))).collect(Collectors.toList());
        if (!StringUtils.isEmpty(categoryCode3))
            prodDataToStatisticsOutPutList = (CollectionUtils.isEmpty(prodDataToStatisticsOutPutList) || CollectionUtils.isEmpty(partCategoryCode3Map)) ? null : prodDataToStatisticsOutPutList.stream().filter(o -> (null != o && partCategoryCode3Map.containsKey(o.getPartNo()))).collect(Collectors.toList());
        return prodDataToStatisticsOutPutList;
    }

    private Map<String, List<SxProdDataToStatisticsOutPutModel>> getOutPutDataMapByDataDimension(SxCompleteRateChartModel data, List<SxProdDataToStatisticsOutPutModel> outPutStatisticsList) {
        if (CollectionUtils.isEmpty(outPutStatisticsList)) return null;
        if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(data.getFlag())) {
            switch (DIMENSION1.getByCode(data.getDimension1())) {
                case DATE:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getPartNo()).toString()));
                case IS_DONT:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).add(o.getPartNo()).toString()));
                case DONT_CLASS:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).add(o.getDontClass()).add(o.getPartNo()).toString()));
                default:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).add(o.getDontClass()).add(o.getWorkCenterCode()).add(o.getPartNo()).toString()));
            }
        } else {
            switch (DIMENSION1.getByCode(data.getDimension1())) {
                case DATE:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).toString()));
                case IS_DONT:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).toString()));
                case DONT_CLASS:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).add(o.getDontClass()).toString()));
                default:
                    return outPutStatisticsList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                            new StringJoiner(MesExtConstWords.AND).add(o.getGroupInfo()).add(o.getCategoryCode3()).add(o.getIsDont()).add(o.getDontClass()).add(o.getWorkCenterCode()).toString()));
            }
        }

    }

    private String getGroupInfo3(SxCompleteRateChartModel data, String workTime) {
        if (!StringUtils.isEmpty(data.getUnGroupByDate()))
            return !data.getWorkTimeStart().equals(data.getWorkTimeEnd()) ? new StringJoiner("~").add(data.getWorkTimeStart()).add(data.getWorkTimeEnd()).toString() : data.getWorkTimeStart();

        switch (DIMENSION.getByCode(data.getDimension())) {
            case YEAR:
                String year = workTime.substring(0, 4);
                if (!data.getSxYearFlag()) return year;
                else {
                    workTime = workTime.length() == 7 ? workTime + MesExtConstWords.DATE_DD_01 : workTime;
                    if (workTime.compareTo(year + MesExtConstWords.DATE_MM_DD_04_01) >= 0) return year;
                    else return String.valueOf(Integer.parseInt(year) - 1);
                }
            case MONTH:
                return workTime.substring(0, 7);
            default:
                return workTime.substring(0, 10);
        }
    }

    private void handleTableNameList(SxCompleteRateChartModel data) {
        data.addTableName(MesExtConstWords.WORK_TIME, "工作时间").addTableName("categoryCode3Name", "产品类别");
        if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(data.getFlag())) data.addTableName(MesExtConstWords.PART_NO, "物料编码").addTableName(MesExtConstWords.PART_NAME_RDD, "物料名称");
        if (data.getDimension1() >= DIMENSION1.IS_DONT.code) data.addTableName(MesExtConstWords.IS_DONT, "系别");
        if (data.getDimension1() >= DIMENSION1.DONT_CLASS.code) data.addTableName(MesExtConstWords.DONT_CLASS, "班别");
        if (data.getDimension1() == DIMENSION1.CENTER.code) data.addTableName(MesExtConstWords.WORK_CENTER_CODE, "生产线代码").addTableName(MesExtConstWords.WORK_CENTER_NAME, "生产线名称");
        data.addTableName("planQty", "计划").addTableName(MesExtConstWords.QTY, "实绩").addTableName("attainmentRate", "达成率");
        if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValueStr().equals(data.getFlag())) data.addTableName("completeRate", "完结率");
    }

    private void handleTableDataList(SxCompleteRateChartModel data, Map<String, String> categoryCode3Map, Map<String, MesWorkCenterExt> centerMap, Map<String, List<SxProdDataToStatisticsOutPutModel>> listMap) {

        for (Map.Entry<String, List<SxProdDataToStatisticsOutPutModel>> entry : listMap.entrySet()) {

            List<SxProdDataToStatisticsOutPutModel> itemList = entry.getValue();

            String[] keyArr = entry.getKey().split(MesExtConstWords.AND);
            String categoryCode3 = keyArr.length > 1 ? keyArr[1] : MesExtConstWords.EMPTY;
            SxCompleteRateDetailModel tableData = new SxCompleteRateDetailModel(keyArr[0], categoryCode3, getCategoryCode3Name(categoryCode3Map, categoryCode3));
            if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(data.getFlag())) tableData.partNo(keyArr[keyArr.length - 1], itemList.get(0).getPartNameRdd());
            if (data.getDimension1() >= DIMENSION1.IS_DONT.code) tableData.isDont(keyArr[2]);
            if (data.getDimension1() >= DIMENSION1.DONT_CLASS.code) tableData.dontClass(keyArr[3]);
            if (data.getDimension1() == DIMENSION1.CENTER.code) tableData.workCenterCode(keyArr[4], centerMap.get(keyArr[4]).getWorkCenterName());
            tableData.planQty(getPlanQtyAmount(itemList)).qty(getCompleteQtyAmount(itemList)).attainmentRate(getBigDecimalPercent(divThenMul100Format2RoundHalfUp(tableData.getQty(), tableData.getPlanQty())));
            if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValueStr().equals(data.getFlag())) tableData.completeRate(getBigDecimalPercent(getCompleteRate(itemList)));

            data.addTableData(tableData);
        }

    }

    private String getCategoryCode3Name(Map<String, String> categoryCode3Map, String categoryCode3) {
        return CollectionUtils.isEmpty(categoryCode3Map) ? null : categoryCode3Map.get(categoryCode3);
    }

    enum DIMENSION {

        YEAR(10, "年"),
        MONTH(20, "月"),
        DAY(30, "日");

        private Integer code;
        private String description;

        DIMENSION(Integer code, String description) {
            this.code = code;
            this.description = description;
        }

        public static SxCategoryCompleteRateService.DIMENSION getByCode(int code) {
            SxCategoryCompleteRateService.DIMENSION[] var1 = values();
            int var2 = var1.length;

            for (int var3 = 0; var3 < var2; ++var3) {
                SxCategoryCompleteRateService.DIMENSION dimension = var1[var3];
                if (dimension.getCode() == code) {
                    return dimension;
                }
            }
            return null;
        }

        public int getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

    }

    enum DIMENSION1 {

        DATE(10, "日期"),
        IS_DONT(20, "系别"),
        DONT_CLASS(30, "班别"),
        CENTER(40, "产线");

        private Integer code;
        private String description;

        DIMENSION1(Integer code, String description) {
            this.code = code;
            this.description = description;
        }

        public static DIMENSION1 getByCode(int code) {
            DIMENSION1[] var1 = values();
            int var2 = var1.length;

            for (int var3 = 0; var3 < var2; ++var3) {
                DIMENSION1 dimension = var1[var3];
                if (dimension.getCode() == code) {
                    return dimension;
                }
            }
            return null;
        }

        public int getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

    }
}
