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

import cn.estsh.i3plus.ext.mes.api.base.jx.IJxRepairJudgeTypeService;
import cn.estsh.i3plus.ext.mes.api.busi.ISxBadStatisticsReportFormService;
import cn.estsh.i3plus.ext.mes.api.busi.jx.IJxBadStatisticsReportFormService;
import cn.estsh.i3plus.ext.mes.apiservice.dao.ISxRepairRecordDao;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesBadCell;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesBadCellDetail;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesOutPutStatistics;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesRepairRecordExt;
import cn.estsh.i3plus.ext.mes.pojo.model.BadStatisticsReportModel;
import cn.estsh.i3plus.ext.mes.pojo.model.BadStatisticsReportParamModel;
import cn.estsh.i3plus.ext.mes.pojo.model.ProjectBadPerformanceReportModel;
import cn.estsh.i3plus.ext.mes.pojo.model.SxRepairRecordReportModel;
import cn.estsh.i3plus.ext.mes.pojo.model.jx.JxOqcCheckStatisticsReportModel;
import cn.estsh.i3plus.ext.mes.pojo.model.jx.JxProjectBadPerformanceReportModel;
import cn.estsh.i3plus.ext.mes.pojo.model.jx.SxDynamicAttributeModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesBadCellDetailRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesBadCellRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesOutPutStatisticsRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesRepairRecordExtRepository;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.impp.framework.boot.auth.AuthUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
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;

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

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private MesRepairRecordExtRepository repairRecordExtRepository;

    @Autowired
    private IJxRepairJudgeTypeService repairJudgeTypeService;

    @Override
    public JxProjectBadPerformanceReportModel queryProjectBadPerformance(BadStatisticsReportParamModel model) {
        JxProjectBadPerformanceReportModel result = null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        if (!StringUtils.isEmpty(model.getWorkTimeStart()) || !StringUtils.isEmpty(model.getWorkTimeEnd())) {
            DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesExtConstWords.WORK_TIME, packBean, false);
        }

        List<MesRepairRecordExt> repairRecordExtList = repairRecordExtRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(repairRecordExtList)) {
            log.info("工程不良实绩未查询到维修数据,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
            return result;
        }

        result = new JxProjectBadPerformanceReportModel();

        log.info("工程不良实绩已查询到维修数据,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
        packRepairRecordWorkTime(repairRecordExtList, model);

        Map<String, List<MesRepairRecordExt>> repairRecordMap = packRepairRecordMap(repairRecordExtList);

        List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRepository.findByHqlWhere(packBean);
        Map<String, List<MesOutPutStatistics>> outPutStatisticsMap = null;
        if (!CollectionUtils.isEmpty(outPutStatisticsList)) {
            log.info("工程不良实绩已查询到产量数据,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
            packOutPutStatisticsWorkTime(outPutStatisticsList, model);

            outPutStatisticsMap = packOutPutStatisticsMapForProjectBadPerformance(outPutStatisticsList);
        } else {
            log.info("工程不良实绩未查询到产量数据,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
        }

        // 维修判定map
        Map<String, String> repairJudgeMap = repairJudgeTypeService.queryRepairJudgeMap(model.getOrganizeCode());

        packBaseAttributeList4ProjectBadStatistics(result, repairJudgeMap);

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

        for (String key : repairRecordMap.keySet()) {
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            List<MesRepairRecordExt> itemList = repairRecordMap.get(key);
            if (CollectionUtils.isEmpty(itemList)) {
                continue;
            }

            String[] keyArr = key.split(MesExtConstWords.AND);
            //ProjectBadPerformanceReportModel result = new ProjectBadPerformanceReportModel();

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

            resultMap.put(MesExtConstWords.WORK_TIME, keyArr[0]);
            resultMap.put(MesExtConstWords.WORK_CENTER_CODE, keyArr[1]);

            //result.setWorkTime(keyArr[0]);
            //result.setWorkCenterCode(keyArr[1]);

            List<MesOutPutStatistics> itemOutPutStatisticsList = CollectionUtils.isEmpty(outPutStatisticsMap) ? null : outPutStatisticsMap.get(key);
            //总产量
            //result.setQty(getQty(itemOutPutStatisticsList));
            resultMap.put(MesExtConstWords.QTY, getQty(itemOutPutStatisticsList));
            //误判数
            //result.setMisjudgeQty(getBadQtyByType(itemList, MesExtEnumUtil.REPAIR_JUDGE.MISJUDGE.getValue()));
            if (!CollectionUtils.isEmpty(repairJudgeMap)) {
                for (Map.Entry<String, String> entry : repairJudgeMap.entrySet()) {
                    resultMap.put(entry.getKey(), getBadQtyByType(itemList, entry.getKey()));
                    resultMap.put(entry.getKey() + "Rate", getRateDecimalOne((Double)resultMap.get(entry.getKey()), (Double)resultMap.get(MesExtConstWords.QTY)));
                }
            }
            ////误判率
            //result.setMisjudgeRate(getRateDecimalOne(result.getMisjudgeQty(), result.getQty()));
            ////部品不良数
            //result.setPartsBadQty(getBadQtyByType(itemList, MesExtEnumUtil.REPAIR_JUDGE.PARTS_BAD.getValue()));
            ////部品不良率
            //result.setPartsBadRate(getRateDecimalOne(result.getPartsBadQty(), result.getQty()));
            ////作业不良数
            //result.setTaskBadQty(getBadQtyByType(itemList, MesExtEnumUtil.REPAIR_JUDGE.TASK_BAD.getValue()));
            //作业不良率
            //result.setTaskBadRate(getRateDecimalOne(result.getTaskBadQty(), result.getQty()));
            //总不良率
            resultMap.put(MesExtConstWords.AMOUNT_BAD_RATE, getRateDecimalOne(CollectionUtils.isEmpty(itemList) ? new Double(0) : new Double(itemList.size()), (Double)resultMap.get(MesExtConstWords.QTY)));
            //result.setAmountBadRate(getRateDecimalOne(CollectionUtils.isEmpty(itemList) ? new Double(0) : new Double(itemList.size()), result.getQty()));

            resultMapList.add(resultMap);
            //resultList.add(result);
        }

        log.info("工程不良实绩报表数据开始重新排序,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
        if (!CollectionUtils.isEmpty(resultMapList)) {
            resultMapList = sortProjectBadPerformanceResult(resultMapList);
            log.info("不良统计报表数据重新排序成功,维度[{}]", MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.valueOfDescription(model.getDimension()));
        }
        result.setDataList(resultMapList);
        return result;
    }

    private void packBaseAttributeList4ProjectBadStatistics(JxProjectBadPerformanceReportModel model, Map<String, String> repairJudgeMap) {
        model.addAttribute(new SxDynamicAttributeModel("生产日期", MesExtConstWords.WORK_TIME))
                .addAttribute(new SxDynamicAttributeModel("产线代码", MesExtConstWords.WORK_CENTER_CODE))
                .addAttribute(new SxDynamicAttributeModel("总产量", MesExtConstWords.QTY));

        if (!CollectionUtils.isEmpty(repairJudgeMap)) {
            for (Map.Entry<String, String> entry : repairJudgeMap.entrySet()) {
                model.addAttribute(new SxDynamicAttributeModel(entry.getValue(), entry.getKey()));
                model.addAttribute(new SxDynamicAttributeModel(entry.getValue() + "率", entry.getKey()+ "Rate"));
            }
        }

        model.addAttribute(new SxDynamicAttributeModel("总不良率", MesExtConstWords.AMOUNT_BAD_RATE));
    }

    private List<Map<String, Object>> sortProjectBadPerformanceResult(List<Map<String, Object>> resultMapList) {

        //Collections.sort(resultMapList, new Comparator<Map<String, Object>>() {
        //    @Override
        //    public int compare(Map<String, Object> map1, Map<String, Object> map2) {
        //        String workTime1 = (String) map1.get(MesExtConstWords.WORK_TIME);
        //        String workTime2w = (String) map2.get(MesExtConstWords.WORK_TIME);
        //        int result = workTime1.compareTo(workTime2w);
        //        if (result == 0) {
        //            String workCenterCode1 = (String) map1.get(MesExtConstWords.WORK_CENTER_CODE);
        //            String workCenterCode2 = (String) map2.get(MesExtConstWords.WORK_CENTER_CODE);
        //            return workCenterCode1.compareTo(workCenterCode2);
        //        }
        //        return result;
        //    }
        //});

        return resultMapList.stream().sorted(
                Comparator.comparing(m -> new StringJoiner(MesExtConstWords.AND).add((String) m.get(MesExtConstWords.WORK_TIME)).add((String)m.get(MesExtConstWords.WORK_CENTER_CODE)).toString())
        ).collect(Collectors.toList());
    }

    private Double getBadQtyByType(List<MesRepairRecordExt> itemList, String type) {
        List<MesRepairRecordExt> list = CollectionUtils.isEmpty(itemList) ? null :
                itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getRepairJudgeCode()) && o.getRepairJudgeCode().compareTo(type) == 0)).collect(Collectors.toList());
        return CollectionUtils.isEmpty(list) ? new Double(0) : new Double(list.size());
    }

    private Map<String, List<MesRepairRecordExt>> packRepairRecordMap(List<MesRepairRecordExt> repairRecordExtList) {
        return repairRecordExtList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()) && !StringUtils.isEmpty(o.getWorkCenterCode())))
                .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTime()).add(o.getWorkCenterCode()).toString())));
    }

    private void packRepairRecordWorkTime(List<MesRepairRecordExt> repairRecordExtList, BadStatisticsReportParamModel model) {
        if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.MONTH.getValue() == model.getDimension()) {
            repairRecordExtList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()))).forEach(o -> {
                o.setWorkTime(o.getWorkTime().substring(0, 7));
            });
        }
    }

    private void packOutPutStatisticsWorkTime(List<MesOutPutStatistics> outPutStatisticsList, BadStatisticsReportParamModel model) {
        if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH.MONTH.getValue() == model.getDimension()) {
            outPutStatisticsList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()))).forEach(o -> {
                o.setWorkTime(o.getWorkTime().substring(0, 7));
            });
        }
    }

    private Map<String, List<MesOutPutStatistics>> packOutPutStatisticsMapForProjectBadPerformance(List<MesOutPutStatistics> outPutStatisticsList) {
        return outPutStatisticsList.stream().filter(o -> (null != o &&
                !StringUtils.isEmpty(o.getWorkTime()) && !StringUtils.isEmpty(o.getWorkCenterCode())))
                .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTime()).add(o.getWorkCenterCode()).toString())));
    }

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

    private String getRateDecimalOne(Double d1, Double d2) {
        if (StringUtils.isEmpty(d2) || MathOperation.compareTo(d2, new Double(0)) == 0) {
            return null;
        }
        return MathOperation.div(MathOperation.mul(d1, 100), d2, 1) + MesExtConstWords.PERCENT;
    }

    private List<BadStatisticsReportModel> sortBadStatisticsResult(List<BadStatisticsReportModel> resultList, Integer dimension) {
        switch (MesExtEnumUtil.BAD_STATISTICS_REPORT_DIMENSION.getByValue(dimension)) {
            case CELL:
                resultList = resultList.stream().sorted(Comparator.comparing(BadStatisticsReportModel::getWorkTime)
                        .thenComparing(BadStatisticsReportModel::getShiftCode)
                        .thenComparing(BadStatisticsReportModel::getWorkCenterCode)
                        .thenComparing(BadStatisticsReportModel::getWorkCellCode)
                        .thenComparing(BadStatisticsReportModel::getPartNo)).collect(Collectors.toList());
                break;
            case CENTER:
            default:
                resultList = resultList.stream().sorted(Comparator.comparing(BadStatisticsReportModel::getWorkTime)
                        .thenComparing(BadStatisticsReportModel::getShiftCode)
                        .thenComparing(BadStatisticsReportModel::getWorkCenterCode)
                        .thenComparing(BadStatisticsReportModel::getPartNo)).collect(Collectors.toList());
                break;
        }
        return resultList;
    }
}
