package com.jiayue.ipp.idp.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiayue.ipp.common.data.entity.*;
import com.jiayue.ipp.idp.mapper.AccuracyCalculationMapper;
import com.jiayue.ipp.idp.service.*;
import com.jiayue.ipp.idp.util.DateTimeUtil;
import com.syjy.calculate.entity.CalculateRequest;
import com.syjy.calculate.entity.CalculateResult;
import com.syjy.calculate.entity.CalculationFormula;
import com.syjy.calculate.entity.CalculationInfo;
import com.syjy.calculate.repository.CalculationFormulaRepository;
import com.syjy.calculate.service.AccuracyPassRateCalculateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * idp_accuracy_calculation
 *
 * @author whc
 * @date 2022-10-17 15:08:48
 */
@Service
public class AccuracyCalculationServiceImpl extends ServiceImpl<AccuracyCalculationMapper, AccuracyCalculation> implements AccuracyCalculationService {
    @Autowired
    AccuracyPassRateCalculateService accuracyPassRateCalculateService;
    @Autowired
    ForecastPowerShortTermHisService forecastPowerShortTermHisService;
    @Autowired
    ForecastPowerUltraShortTermHisService forecastPowerUltraShortTermHisService;
    @Autowired
    PowerStationStatusDataService powerStationStatusDataService;
    @Autowired
    CalculationFormulaRepository calculationFormulaRepository;
    @Autowired
    SysParameterService sysParameterService;
    @Autowired
    ElectricFieldService electricFieldService;
    long moment15 = 900000L;


    /**
     * 根据时间查询日准确率合格率 (表格)
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param sortOrder 排序
     * @return
     */
    @Override
    public Map<String, Object> findByTimeBetweenTableDay(Long startTime, Long endTime,
                                                         String showCode,
                                                         String sortOrder,
                                                         String stationCode,
                                                         String type,
                                                         String forecastManufactor) {
        Map<String, Object> map = new HashMap<>();
        List<AccuracyCalculation> byTimeBetween = new ArrayList<>();

        long timeStep = 900000L;
        if (startTime % timeStep != 0) {
            startTime = startTime - (startTime % timeStep) + timeStep;
        }
        if (endTime % timeStep != 0) {
            endTime = endTime - (endTime % timeStep);
        }
        // 根据时间，获取准确率数据
        byTimeBetween = findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime), type, forecastManufactor);
        // 补全日数据
        List<AccuracyCalculation> allList = checkDataDay(startTime, endTime, byTimeBetween);
        //DAY  按照一天1条显示 也就是每天23:45那条    TIME  按照15分钟一条展示

        List<AccuracyCalculation> accuracyPassRateDayList = new ArrayList<>();
        SimpleDateFormat sdf;
        if (type.equals("day")) {
            accuracyPassRateDayList.addAll(allList);
            sdf = new SimpleDateFormat("yyyy-MM-dd");

        } else {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            accuracyPassRateDayList = allList;
        }

        if (sortOrder.contains("asc")) {
            accuracyPassRateDayList.sort(Comparator.comparing(AccuracyCalculation::getTime));
        } else {
            accuracyPassRateDayList.sort(Comparator.comparing(AccuracyCalculation::getTime).reversed());
        }

        List<Map<String, Object>> resultList = new ArrayList<>();
        String[] displayCode = showCode.split(",");

        List<String> shortTermAccuracys = new ArrayList<>();
        List<String> shortTermPassRate = new ArrayList<>();
        List<String> ultraShortTermAccuracy = new ArrayList<>();
        List<String> ultraShortTermPassRate = new ArrayList<>();
        List<String> times = new ArrayList<>();
        Map<String, Object> chartsMap = new HashMap<>();
        String accuracyRate = sysParameterService.getSysParameterAndStationCode("ACCURACY_RATE", "75,85", stationCode);
        chartsMap.put("accuracyRate", accuracyRate);
        for (AccuracyCalculation accuracyCalculation : accuracyPassRateDayList) {
            Map<String, Object> dtoM = new HashMap<>();
            AccuracyCalculation apr = accuracyCalculation;
            dtoM.put("time", sdf.format(apr.getTime()));
            times.add(sdf.format(apr.getTime()));

            for (String s : displayCode) {

                if (s.equals("shortTermAccuracy")) {
                    dtoM.put(s, apr.getShortTermAccuracy());
                    if (apr.getShortTermAccuracy() != null && apr.getShortTermAccuracy().equals("无可用数计算")) {
                        shortTermAccuracys.add(null);
                    } else {
                        if (apr.getShortTermAccuracy() != null && !apr.getShortTermAccuracy().equals("不予考核")) {
                            shortTermAccuracys.add(apr.getShortTermAccuracy());
                        }
                    }
                }
                if (s.equals("shortTermPassRate")) {
                    dtoM.put(s, apr.getShortTermPass());
                    if (apr.getShortTermPass() != null && apr.getShortTermPass().equals("无可用数计算")) {
                        shortTermPassRate.add(null);
                    } else {
                        shortTermPassRate.add(apr.getShortTermPass());
                    }
                }
                if (s.equals("ultraShortTermAccuracy")) {
                    dtoM.put(s, apr.getUltraShortTermAccuracy());
                    if (apr.getUltraShortTermAccuracy() != null && apr.getUltraShortTermAccuracy().equals("无可用数计算")) {
                        ultraShortTermAccuracy.add(null);
                    } else {
                        if (apr.getShortTermAccuracy() != null && !apr.getUltraShortTermAccuracy().equals("不予考核")) {
                            ultraShortTermAccuracy.add(apr.getUltraShortTermAccuracy());
                        }
                    }
                }
                if (s.equals("ultraShortTermPassRate")) {
                    dtoM.put(s, apr.getUltraShortTermPass());
                    if (apr.getUltraShortTermPass() != null && apr.getUltraShortTermPass().equals("无可用数计算")) {
                        ultraShortTermPassRate.add(null);
                    } else {
                        ultraShortTermPassRate.add(apr.getUltraShortTermPass());
                    }
                }
            }
            resultList.add(dtoM);
        }

        chartsMap.put("times", times);

        for (String s : displayCode) {
            if (s.equals("shortTermAccuracy")) {
                chartsMap.put(s, shortTermAccuracys);
            }
            if (s.equals("shortTermPassRate")) {
                chartsMap.put(s, shortTermPassRate);
            }
            if (s.equals("ultraShortTermAccuracy")) {
                chartsMap.put(s, ultraShortTermAccuracy);
            }
            if (s.equals("ultraShortTermPassRate")) {
                chartsMap.put(s, ultraShortTermPassRate);
            }
        }

        map.put("content", resultList);
        map.put("charts", chartsMap);

        return map;
    }

    /**
     * @param startTime     开始时间
     * @param endTime       结束时间
     * @param byTimeBetween 需要补全时间的数据
     * @param timeStep      时间间隔
     * @return 补全后数据
     */
    private List<AccuracyCalculation> checkData(Long startTime, Long endTime, List<AccuracyCalculation> byTimeBetween, long timeStep) {
        List<AccuracyCalculation> rtList = new ArrayList<>();
        //补全数据
        for (long i = startTime; i <= endTime; i = i + timeStep) {
            long finalI = i;
            List<AccuracyCalculation> a = byTimeBetween.stream().filter(t -> t.getTime().compareTo(getDateTimeOfTimestamp(finalI)) == 0).collect(Collectors.toList());
            if (!a.isEmpty()) {
                AccuracyCalculation aResult = a.get(0);
                rtList.add(aResult);
            } else {
                AccuracyCalculation accuracyPassRate = new AccuracyCalculation();
                accuracyPassRate.setTime(getDateTimeOfTimestamp(finalI));
                rtList.add(accuracyPassRate);
            }
        }
        return rtList;
    }

    /**
     * @param startTime     开始时间
     * @param endTime       结束时间
     * @param byTimeBetween 需要补全时间的数据
     * @return 补全后数据
     */
    private List<AccuracyCalculation> checkDataDay(Long startTime, Long endTime, List<AccuracyCalculation> byTimeBetween) {
        List<AccuracyCalculation> resultList = new ArrayList<>();
        // 根据时间段，将时间段以日期为单位转为list
        List<DateTime> dateTimes = DateUtil.rangeToList(new Date(startTime), new Date(endTime), DateField.DAY_OF_YEAR);
        //补全数据
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 0; i < dateTimes.size(); i++) {
            int finalI = i;
            // 根据准确率数据中，是否包含时间段中的时间(格式化时间为yyyy-MM-dd并对比)
            List<AccuracyCalculation> checkInclude = byTimeBetween.stream().filter(t -> sdf.format(DateUtil.date(t.getTime())).equals(sdf.format(dateTimes.get(finalI)))).sorted(Comparator.comparing(AccuracyCalculation::getId).reversed()).collect(Collectors.toList());
            // 如果包含，则放入数据
            if (!checkInclude.isEmpty()) {
                // 获取最新一条
                AccuracyCalculation aResult = checkInclude.get(0);
                resultList.add(aResult);
                // 如果不包含，则只插入时间
            } else {
                AccuracyCalculation accuracyPassRateDay = new AccuracyCalculation();
                accuracyPassRateDay.setTime(getDateTimeOfTimestamp(dateTimes.get(finalI).getTime()));
                resultList.add(accuracyPassRateDay);
            }
        }
        return resultList;
    }

    /**
     * 更换数据
     *
     * @param rateList 需要更换数据的集合
     */
    private void exchangeValue(List<AccuracyCalculation> rateList) {
        for (AccuracyCalculation accuracyCalculation : rateList) {
            String shortTermAccuracy = accuracyCalculation.getShortTermAccuracy();
            String ultraShortTermAccuracy = accuracyCalculation.getUltraShortTermAccuracy();
            String shortTermPassRate = accuracyCalculation.getShortTermPass();
            String ultraShortTermPassRate = accuracyCalculation.getUltraShortTermPass();
            if (shortTermAccuracy != null && shortTermAccuracy.equals("无可用数计算")) {
                accuracyCalculation.setShortTermAccuracy(null);
            }
            if (ultraShortTermAccuracy != null && ultraShortTermAccuracy.equals("无可用数计算")) {
                accuracyCalculation.setUltraShortTermAccuracy(null);
            }
            if (shortTermPassRate != null && shortTermPassRate.equals("无可用数计算")) {
                accuracyCalculation.setShortTermPass(null);
            }
            if (ultraShortTermPassRate != null && ultraShortTermPassRate.equals("无可用数计算")) {
                accuracyCalculation.setUltraShortTermPass(null);
            }
        }
    }

    /**
     * 更换数据
     *
     * @param rateList 需要更换数据的集合
     */
    private void exchangeValueDay(List<AccuracyCalculation> rateList) {
        for (AccuracyCalculation accuracyCalculation : rateList) {
            String shortTermAccuracy = accuracyCalculation.getShortTermAccuracy();
            String ultraShortTermAccuracy = accuracyCalculation.getUltraShortTermAccuracy();
            String shortTermPassRate = accuracyCalculation.getShortTermPass();
            String ultraShortTermPassRate = accuracyCalculation.getUltraShortTermPass();
            if (shortTermAccuracy != null && shortTermAccuracy.equals("无可用数计算")) {
                accuracyCalculation.setShortTermAccuracy(null);
            }
            if (ultraShortTermAccuracy != null && ultraShortTermAccuracy.equals("无可用数计算")) {
                accuracyCalculation.setUltraShortTermAccuracy(null);
            }
            if (shortTermPassRate != null && shortTermPassRate.equals("无可用数计算")) {
                accuracyCalculation.setShortTermPass(null);
            }
            if (ultraShortTermPassRate != null && ultraShortTermPassRate.equals("无可用数计算")) {
                accuracyCalculation.setUltraShortTermPass(null);
            }
        }
    }

    /**
     * 超短期准确率,合格率
     * @return
     */
    @Override
    public List<AccuracyCalculation> homePageUltraShortAccuracy() {
        List<AccuracyCalculation> returnList = new ArrayList<>();
        Long date = new Date().getTime();
        //今日0点
        Date start = DateTimeUtil.getDayStartTime(date);
        //今日23点59
        Date end = DateTimeUtil.getDayLastTime(date);
        //日
        String dayType = "day";
        //单点
        String pointType = "point";
        List<ElectricField> electricFieldList = electricFieldService.list();
        for (ElectricField e : electricFieldList) {
            List<AccuracyCalculation> accuracyCalculationList;
            List<AccuracyCalculation> collect;
            //先查该场站有没有日的准确率 如果没有再查单点的
            accuracyCalculationList = findByStationCodeAndBetweenTimeAndForecastManufactor(e.getStationCode(), start, end, e.getBelongForecastManufactor());
            //日准确率集合
            List<AccuracyCalculation> dayAcc = accuracyCalculationList.stream().filter(accuracyCalculation -> accuracyCalculation.getType().equals(dayType)).collect(Collectors.toList());
            //单点准确率集合
            List<AccuracyCalculation> pointAcc = accuracyCalculationList.stream().filter(accuracyCalculation -> accuracyCalculation.getType().equals(pointType)).collect(Collectors.toList());
            //通过 day类型的数据集合是否为空 如果不是空 短期超短期准确率不是无计算公式来判断这个站    是单点准确率还是日准确率
            // day 短期准确率:无公式  超短期准确率:无公式      单点准确率
            if (!accuracyCalculationList.isEmpty()  && dayAcc.get(0).getUltraShortTermAccuracy().equals("无计算公式")) {
                AccuracyCalculation accuracyCalculation = calculationPointAve(pointAcc, e.getStationCode(), start);
                returnList.add(accuracyCalculation);
            }
            // day 短期准确率:无/有数据  超短期准确率:无/有数据      日准确率
            else if (!accuracyCalculationList.isEmpty() && pointAcc.get(0).getUltraShortTermAccuracy().equals("无计算公式")) {
                //通过最后修改时间查出最后一条数据
                collect = dayAcc.stream().sorted(Comparator.comparing(AccuracyCalculation::getLastModifyTime).reversed()).collect(Collectors.toList());
                returnList.add(collect.get(0));
            } else if (!accuracyCalculationList.isEmpty()) {
                //单点和日都有的情况
                // point 短期准确率:无/有数据 超短期准确率:无/有数据
                // day   短期准确率:无/有数据 超短期准确率:无/有数据
                AccuracyCalculation accuracyCalculation = calculationPointAve(pointAcc, e.getStationCode(), start);
                //通过最后修改时间查出最后一条数据
                collect = dayAcc.stream().sorted(Comparator.comparing(AccuracyCalculation::getLastModifyTime).reversed()).collect(Collectors.toList());
                returnList.add(collect.get(0));
                returnList.add(accuracyCalculation);
            }
        }
        List<AccuracyCalculation> list = returnList.stream().sorted(Comparator.comparing(AccuracyCalculation::getUltraShortTermAccuracy)).collect(Collectors.toList());
        List<AccuracyCalculation> listSymbol = list.stream().filter(s->s.getUltraShortTermAccuracy().contains("%")).collect(Collectors.toList());
        List<AccuracyCalculation> listChinese = list.stream().filter(s->!s.getUltraShortTermAccuracy().contains("%")).collect(Collectors.toList());
        listSymbol.stream().sorted(Comparator.comparing(AccuracyCalculation::getUltraShortTermAccuracy).reversed()).collect(Collectors.toList());
        listChinese.addAll(listSymbol);

        return listChinese;
    }

    /**
     * 短期准确率,合格率
     * @return
     */
    @Override
    public List<AccuracyCalculation> homePageShortAccuracy() {
        List<AccuracyCalculation> returnList = new ArrayList<>();
        Long date = new Date().getTime();
        //今日0点
        Date start = DateTimeUtil.getDayStartTime(date);
        //今日23点59
        Date end = DateTimeUtil.getDayLastTime(date);
        //日
        String dayType = "day";
        //单点
        String pointType = "point";
        List<ElectricField> electricFieldList = electricFieldService.list();
        for (ElectricField e : electricFieldList) {
            List<AccuracyCalculation> accuracyCalculationList;
            List<AccuracyCalculation> collect;
            //先查该场站有没有日的准确率 如果没有再查单点的
            accuracyCalculationList = findByStationCodeAndBetweenTimeAndForecastManufactor(e.getStationCode(), start, end, e.getBelongForecastManufactor());
            //日准确率集合
            List<AccuracyCalculation> dayAcc = accuracyCalculationList.stream().filter(accuracyCalculation -> accuracyCalculation.getType().equals(dayType)).collect(Collectors.toList());
            //单点准确率集合
            List<AccuracyCalculation> pointAcc = accuracyCalculationList.stream().filter(accuracyCalculation -> accuracyCalculation.getType().equals(pointType)).collect(Collectors.toList());
            //通过 day类型的数据集合是否为空 如果不是空 短期超短期准确率不是无计算公式来判断这个站    是单点准确率还是日准确率
            // day 短期准确率:无公式  超短期准确率:无公式      单点准确率
            if (!accuracyCalculationList.isEmpty() && dayAcc.get(0).getShortTermAccuracy().equals("无计算公式")) {
                AccuracyCalculation accuracyCalculation = calculationPointAve(pointAcc, e.getStationCode(), start);
                returnList.add(accuracyCalculation);
            }
            // day 短期准确率:无/有数据  超短期准确率:无/有数据      日准确率
            else if (!accuracyCalculationList.isEmpty() && pointAcc.get(0).getShortTermAccuracy().equals("无计算公式")) {
                //通过最后修改时间查出最后一条数据
                collect = dayAcc.stream().sorted(Comparator.comparing(AccuracyCalculation::getLastModifyTime).reversed()).collect(Collectors.toList());
                returnList.add(collect.get(0));
            } else if (!accuracyCalculationList.isEmpty()) {
                //单点和日都有的情况
                // point 短期准确率:无/有数据 超短期准确率:无/有数据
                // day   短期准确率:无/有数据 超短期准确率:无/有数据
                AccuracyCalculation accuracyCalculation = calculationPointAve(pointAcc, e.getStationCode(), start);
                //通过最后修改时间查出最后一条数据
                collect = dayAcc.stream().sorted(Comparator.comparing(AccuracyCalculation::getLastModifyTime).reversed()).collect(Collectors.toList());
                returnList.add(collect.get(0));
                returnList.add(accuracyCalculation);
            }
        }


        List<AccuracyCalculation> list = returnList.stream().sorted(Comparator.comparing(AccuracyCalculation::getShortTermAccuracy)).collect(Collectors.toList());
        List<AccuracyCalculation> listSymbol = list.stream().filter(s->s.getShortTermAccuracy().contains("%")).collect(Collectors.toList());
        List<AccuracyCalculation> listChinese = list.stream().filter(s->!s.getShortTermAccuracy().contains("%")).collect(Collectors.toList());
        listSymbol.stream().sorted(Comparator.comparing(AccuracyCalculation::getShortTermAccuracy).reversed()).collect(Collectors.toList());
        listChinese.addAll(listSymbol);

        return listChinese;
    }

    /* 单点计算逻辑为:
                    1.先查出该场站昨日所有的单点数据
                    2.根据属性过滤为四个List集合
                    3.把过滤后的集合里的 无可用数计算 无计算公式过滤出去
                    4.for循环算出总和
                    5.把平均值数据插入到实体中*/
    private AccuracyCalculation calculationPointAve(List<AccuracyCalculation> pointAcc, String stationCode, Date time) {
        BigDecimal shortTermAccuracyCount = new BigDecimal(0);
        BigDecimal ultraShortTermAccuracyCount = new BigDecimal(0);
        BigDecimal shortTermPassCount = new BigDecimal(0);
        BigDecimal ultraShortTermPassCount = new BigDecimal(0);
        AccuracyCalculation accuracyCalculation = new AccuracyCalculation();
        accuracyCalculation.setStationCode(stationCode);
        accuracyCalculation.setType("point");
        accuracyCalculation.setTime(getDateTimeOfTimestamp(time.getTime()));
        if (!pointAcc.isEmpty()) {
            //根据属性过滤出新的集合
            List<String> shortTermAccuracyCollect = pointAcc.stream().map(AccuracyCalculation::getShortTermAccuracy).collect(Collectors.toList());
            List<String> ultraShortTermAccuracyCollect = pointAcc.stream().map(AccuracyCalculation::getUltraShortTermAccuracy).collect(Collectors.toList());
            List<String> shortTermPassCollect = pointAcc.stream().map(AccuracyCalculation::getShortTermPass).collect(Collectors.toList());
            List<String> ultraShortTermPassCollect = pointAcc.stream().map(AccuracyCalculation::getUltraShortTermPass).collect(Collectors.toList());
            //在吧所有集合里的 不予考核  无可用数计算 无计算公式 null 过滤出去
            List<String> shortTermAccuracy = shortTermAccuracyCollect.stream().filter(s -> !s.equals("无可用数计算")).filter(s -> !s.equals("不予考核")).filter(s -> !s.equals("无计算公式")).filter(s -> !s.equals("null")).collect(Collectors.toList());
            List<String> ultraShortTermAccuracy = ultraShortTermAccuracyCollect.stream().filter(s -> !s.equals("无可用数计算")).filter(s -> !s.equals("不予考核")).filter(s -> !s.equals("无计算公式")).filter(s -> !s.equals("null")).collect(Collectors.toList());
            List<String> shortTermPass = shortTermPassCollect.stream().filter(s -> !s.equals("无可用数计算")).filter(s -> !s.equals("不予考核")).filter(s -> !s.equals("无计算公式")).filter(s -> !s.equals("null")).collect(Collectors.toList());
            List<String> ultraShortTermPass = ultraShortTermPassCollect.stream().filter(s -> !s.equals("无可用数计算")).filter(s -> !s.equals("不予考核")).filter(s -> !s.equals("无计算公式")).filter(s -> !s.equals("null")).collect(Collectors.toList());
            //先计算出所有单点的和
            for (String s : shortTermAccuracy) {
                if (s.contains("%")) {
                    shortTermAccuracyCount = shortTermAccuracyCount.add(new BigDecimal(s.replace("%", "")));
                }
            }
            for (String s : ultraShortTermAccuracy) {
                if (s.contains("%")) {
                    ultraShortTermAccuracyCount = ultraShortTermAccuracyCount.add(new BigDecimal(s.replace("%", "")));
                }
            }
            for (String s : shortTermPass) {
                if (s.contains("%")) {
                    shortTermPassCount = shortTermPassCount.add(new BigDecimal(s.replace("%", "")));
                }
            }
            for (String s : ultraShortTermPass) {
                if (s.contains("%")) {
                    ultraShortTermPassCount = ultraShortTermPassCount.add(new BigDecimal(s.replace("%", "")));
                }
            }
            //计算平均值并插入到实体里
            if (shortTermAccuracyCount.compareTo(new BigDecimal(0)) > 0)
                accuracyCalculation.setShortTermAccuracy(shortTermAccuracyCount.divide(BigDecimal.valueOf(shortTermAccuracy.size()), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString());
            else
                accuracyCalculation.setShortTermAccuracy("无可用数计算");
            if (ultraShortTermAccuracyCount.compareTo(new BigDecimal(0)) > 0)
                accuracyCalculation.setUltraShortTermAccuracy(ultraShortTermAccuracyCount.divide(BigDecimal.valueOf(ultraShortTermAccuracy.size()), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString());
            else
                accuracyCalculation.setUltraShortTermAccuracy("无可用数计算");
            if (shortTermPassCount.compareTo(new BigDecimal(0)) > 0)
                accuracyCalculation.setShortTermPass(shortTermPassCount.divide(BigDecimal.valueOf(shortTermPass.size()), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString());
            else
                accuracyCalculation.setShortTermPass("无可用数计算");
            if (ultraShortTermPassCount.compareTo(new BigDecimal(0)) > 0)
                accuracyCalculation.setUltraShortTermPass(ultraShortTermPassCount.divide(BigDecimal.valueOf(ultraShortTermPass.size()), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString());
            else
                accuracyCalculation.setUltraShortTermPass("无可用数计算");
        } else {
            accuracyCalculation.setShortTermAccuracy("无可用数计算");
            accuracyCalculation.setUltraShortTermAccuracy("无可用数计算");
            accuracyCalculation.setShortTermPass("无可用数计算");
            accuracyCalculation.setUltraShortTermPass("无可用数计算");
        }
        return accuracyCalculation;
    }


    @Override
    public Map<String, Object> findByTimeBetweenTable(Long startTime, Long endTime, String showCode, String sortOrder, String stationCode, String type, String forecastManufactor) {

        List<Map<String, Object>> resultList = new ArrayList<>();
        List<Map<String, Object>> mapList = new ArrayList<>();
        List<AccuracyCalculation> byTimeBetween = new ArrayList<>();
        long timeStep = 900000L;
        if (startTime % timeStep != 0) {
            startTime = startTime - (startTime % timeStep) + timeStep;
        }
        if (endTime % timeStep != 0) {
            endTime = endTime - (endTime % timeStep);
        }
        int interval = DateTimeUtil.getDaysBetweenTwoDate(startTime, endTime);
        for (int i = 0; i <= interval; i++) {
            long timestep = 1000L * 24 * 60 * 60 * i;
            byTimeBetween = findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(stationCode, new Date(startTime + timestep), new Date(startTime + timestep + 1000L * 24 * 60 * 60 - 1000), type, forecastManufactor);
            List<AccuracyCalculation> allList = checkData(startTime, endTime, byTimeBetween, timeStep);
            List<AccuracyCalculation> result = new ArrayList<>();
            String sdfs;
            if (type.equals("day")) {
                sdfs = "yyyy-MM-dd";
                //如果是日的 拿最后一条数据
                List<AccuracyCalculation> collect = byTimeBetween.stream().sorted(Comparator.comparing(AccuracyCalculation::getLastModifyTime)).collect(Collectors.toList());
                if (!collect.isEmpty()) {
                    result.add(collect.get(collect.size() - 1));
                }
            } else {
                sdfs = "yyyy-MM-dd HH:mm:ss";
                result = allList;
            }

            if (sortOrder.contains("asc")) {
                result.sort(Comparator.comparing(AccuracyCalculation::getTime));
            } else {
                result.sort(Comparator.comparing(AccuracyCalculation::getTime).reversed());
            }


            String[] displayCode = showCode.split(",");

            List<String> shortTermAccuracys = new ArrayList<>();
            List<String> shortTermPassRate = new ArrayList<>();
            List<String> ultraShortTermAccuracy = new ArrayList<>();
            List<String> ultraShortTermPassRate = new ArrayList<>();
            List<String> times = new ArrayList<>();
            String accuracyRate = sysParameterService.getSysParameterAndStationCode("ACCURACY_RATE", "75,85", stationCode);
            Map<String, Object> chartsMap = new HashMap<>();
            chartsMap.put("accuracyRate", accuracyRate);
            for (AccuracyCalculation accuracyCalculation : result) {
                Map<String, Object> dtoM = new HashMap<>();
                AccuracyCalculation apr = accuracyCalculation;
                dtoM.put("time", apr.getTime().format(DateTimeFormatter.ofPattern(sdfs)));
                times.add(apr.getTime().format(DateTimeFormatter.ofPattern(sdfs)));
                for (String s : displayCode) {
                    if (s.equals("shortTermAccuracy")) {
                        dtoM.put(s, apr.getShortTermAccuracy());
                        if (apr.getShortTermAccuracy() != null && apr.getShortTermAccuracy().equals("无可用数计算")) {
                            shortTermAccuracys.add(null);
                        } else {
                            if (apr.getShortTermAccuracy() != null && !apr.getShortTermAccuracy().equals("不予考核")) {
                                shortTermAccuracys.add(apr.getShortTermAccuracy());
                            }

                        }

                    }
                    if (s.equals("shortTermPass")) {
                        dtoM.put(s, apr.getShortTermPass());
                        if (apr.getShortTermPass() != null && apr.getShortTermPass().equals("无可用数计算")) {
                            shortTermPassRate.add(null);
                        } else {
                            shortTermPassRate.add(apr.getShortTermPass());
                        }
                    }
                    if (s.equals("ultraShortTermAccuracy")) {
                        dtoM.put(s, apr.getUltraShortTermAccuracy());
                        if (apr.getUltraShortTermAccuracy() != null && apr.getUltraShortTermAccuracy().equals("无可用数计算")) {
                            ultraShortTermAccuracy.add(null);
                        } else {
                            if (apr.getShortTermAccuracy() != null && !apr.getUltraShortTermAccuracy().equals("不予考核")) {
                                ultraShortTermAccuracy.add(apr.getUltraShortTermAccuracy());
                            }

                        }
                    }
                    if (s.equals("ultraShortTermPass")) {
                        dtoM.put(s, apr.getUltraShortTermPass());
                        if (apr.getUltraShortTermPass() != null && apr.getUltraShortTermPass().equals("无可用数计算")) {
                            ultraShortTermPassRate.add(null);
                        } else {
                            ultraShortTermPassRate.add(apr.getUltraShortTermPass());
                        }
                    }
                }
                List<ElectricField> electricFieldList = electricFieldService.list().stream().filter(e -> e.getStationCode().equals(stationCode)).collect(Collectors.toList());
                dtoM.put("stationCode", electricFieldList.get(0).getName());
                resultList.add(dtoM);
            }

            chartsMap.put("times", times);

            for (String s : displayCode) {
                if (s.equals("shortTermAccuracy")) {
                    chartsMap.put(s, shortTermAccuracys);
                }
                if (s.equals("shortTermPassRate")) {
                    chartsMap.put(s, shortTermPassRate);
                }
                if (s.equals("ultraShortTermAccuracy")) {
                    chartsMap.put(s, ultraShortTermAccuracy);
                }
                if (s.equals("ultraShortTermPassRate")) {
                    chartsMap.put(s, ultraShortTermPassRate);
                }
            }
            mapList.add(chartsMap);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("content", resultList);
        map.put("charts", mapList);
        return map;
    }

    @Override
    public Map<String, Object> findByTimeBetweenTableMonth(Long startTime, Long endTime, String showCode, String sortOrder, String stationCode, String type, String forecastManufactor) {
        Map<String, Object> map = new HashMap<>();
        List<AccuracyCalculation> allList = new ArrayList<>();

        long timeStep = 900000L;
        if (startTime % timeStep != 0) {
            startTime = startTime - (startTime % timeStep) + timeStep;
        }
        if (endTime % timeStep != 0) {
            endTime = endTime - (endTime % timeStep);
        }

        allList = findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime), type, forecastManufactor);


        List<AccuracyCalculation> result = new ArrayList<>();
        SimpleDateFormat sdf;

        sdf = new SimpleDateFormat("yyyy-MM");
        DecimalFormat df = new DecimalFormat("0.00");

        List<DateTime> dateTimes = DateUtil.rangeToList(new Date(startTime), new Date(endTime), DateField.MONTH);
        for (DateTime dateTime : dateTimes) {
            String format = sdf.format(dateTime);
            List<AccuracyCalculation> collect = allList.stream().filter(s -> sdf.format(s.getTime()).equals(format)).collect(Collectors.toList());

            List<Double> shortTermAccuracyList = new ArrayList<>();
            List<Double> shortTermPassRateList = new ArrayList<>();
            List<Double> ultraShortTermAccuracyList = new ArrayList<>();
            List<Double> ultraShortTermPassRateList = new ArrayList<>();

            for (AccuracyCalculation accuracyPassRate : collect) {
                if (accuracyPassRate.getShortTermAccuracy() != null) {
                    if (accuracyPassRate.getShortTermAccuracy().contains("%")) {
                        try {
                            shortTermAccuracyList.add(Double.parseDouble(accuracyPassRate.getShortTermAccuracy().split("%")[0]));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (accuracyPassRate.getShortTermPass() != null) {
                    if (accuracyPassRate.getShortTermPass().contains("%")) {
                        try {
                            shortTermPassRateList.add(Double.parseDouble(accuracyPassRate.getShortTermPass().split("%")[0]));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }
                if (accuracyPassRate.getUltraShortTermAccuracy() != null) {
                    if (accuracyPassRate.getUltraShortTermAccuracy().contains("%")) {
                        try {
                            ultraShortTermAccuracyList.add(Double.parseDouble(accuracyPassRate.getUltraShortTermAccuracy().split("%")[0]));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }
                if (accuracyPassRate.getUltraShortTermPass() != null) {
                    if (accuracyPassRate.getUltraShortTermPass().contains("%")) {
                        try {
                            ultraShortTermPassRateList.add(Double.parseDouble(accuracyPassRate.getUltraShortTermPass().split("%")[0]));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                }
            }


            AccuracyCalculation newAccuracyPassRate = new AccuracyCalculation();
            if (!shortTermAccuracyList.isEmpty()) {
                double shortTermAccuracyAvg = shortTermAccuracyList.stream().mapToDouble(d -> d.doubleValue()).average().getAsDouble();
                newAccuracyPassRate.setShortTermAccuracy(df.format(shortTermAccuracyAvg) + "%");
            } else {
                newAccuracyPassRate.setShortTermAccuracy("无可用数据");
            }
            if (!shortTermPassRateList.isEmpty()) {
                double shortTermPassRateAvg = shortTermPassRateList.stream().mapToDouble(d -> d.doubleValue()).average().getAsDouble();
                newAccuracyPassRate.setShortTermPass(df.format(shortTermPassRateAvg) + "%");
            } else {
                newAccuracyPassRate.setShortTermPass("无可用数据");
            }
            if (!ultraShortTermAccuracyList.isEmpty()) {
                double ultraShortTermAccuracyAvg = ultraShortTermAccuracyList.stream().mapToDouble(d -> d.doubleValue()).average().getAsDouble();
                newAccuracyPassRate.setUltraShortTermAccuracy(df.format(ultraShortTermAccuracyAvg) + "%");
            } else {
                newAccuracyPassRate.setUltraShortTermAccuracy("无可用数据");
            }
            if (!ultraShortTermPassRateList.isEmpty()) {
                double ultraShortTermPassRateAvg = ultraShortTermPassRateList.stream().mapToDouble(d -> d.doubleValue()).average().getAsDouble();
                newAccuracyPassRate.setUltraShortTermPass(df.format(ultraShortTermPassRateAvg) + "%");
            } else {
                newAccuracyPassRate.setUltraShortTermPass("无可用数据");
            }
            newAccuracyPassRate.setTime(dateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());

            result.add(newAccuracyPassRate);
        }

        if (sortOrder.contains("asc")) {
            result.sort(Comparator.comparing(AccuracyCalculation::getTime));
        } else {
            result.sort(Comparator.comparing(AccuracyCalculation::getTime).reversed());
        }

        List<Map<String, Object>> resultList = new ArrayList<>();
        String[] displayCode = showCode.split(",");

        List<String> shortTermAccuracys = new ArrayList<>();
        List<String> shortTermPassRate = new ArrayList<>();
        List<String> ultraShortTermAccuracy = new ArrayList<>();
        List<String> ultraShortTermPassRate = new ArrayList<>();
        List<String> times = new ArrayList<>();
        Map<String, Object> chartsMap = new HashMap<>();
        String accuracyRate = sysParameterService.getSysParameterAndStationCode("ACCURACY_RATE", "75,85", stationCode);
        chartsMap.put("accuracyRate", accuracyRate);
        for (AccuracyCalculation accuracyCalculation : result) {
            Map<String, Object> dtoM = new HashMap<>();
            AccuracyCalculation apr = accuracyCalculation;
            dtoM.put("time", sdf.format(apr.getTime()));
            times.add(sdf.format(apr.getTime()));

            for (String s : displayCode) {
                if (s.equals("shortTermAccuracy")) {
                    dtoM.put(s, apr.getShortTermAccuracy());
                    if (apr.getShortTermAccuracy() != null && apr.getShortTermAccuracy().equals("无可用数计算")) {
                        shortTermAccuracys.add(null);
                    } else {
                        shortTermAccuracys.add(apr.getShortTermAccuracy());
                    }

                }
                if (s.equals("shortTermPassRate")) {
                    dtoM.put(s, apr.getShortTermPass());
                    if (apr.getShortTermPass() != null && apr.getShortTermPass().equals("无可用数计算")) {
                        shortTermPassRate.add(null);
                    } else {
                        shortTermPassRate.add(apr.getShortTermPass());
                    }
                }
                if (s.equals("ultraShortTermAccuracy")) {
                    dtoM.put(s, apr.getUltraShortTermAccuracy());
                    if (apr.getUltraShortTermAccuracy() != null && apr.getUltraShortTermAccuracy().equals("无可用数计算")) {
                        ultraShortTermAccuracy.add(null);
                    } else {
                        ultraShortTermAccuracy.add(apr.getUltraShortTermAccuracy());
                    }
                }
                if (s.equals("ultraShortTermPassRate")) {
                    dtoM.put(s, apr.getUltraShortTermPass());
                    if (apr.getUltraShortTermPass() != null && apr.getUltraShortTermPass().equals("无可用数计算")) {
                        ultraShortTermPassRate.add(null);
                    } else {
                        ultraShortTermPassRate.add(apr.getUltraShortTermPass());
                    }
                }
            }
            resultList.add(dtoM);
        }

        chartsMap.put("times", times);

        for (String s : displayCode) {

            if (s.equals("shortTermAccuracy")) {

                chartsMap.put(s, shortTermAccuracys);
            }

            if (s.equals("shortTermPassRate")) {

                chartsMap.put(s, shortTermPassRate);
            }

            if (s.equals("ultraShortTermAccuracy")) {

                chartsMap.put(s, ultraShortTermAccuracy);
            }

            if (s.equals("ultraShortTermPassRate")) {

                chartsMap.put(s, ultraShortTermPassRate);
            }

        }

        map.put("content", resultList);
        map.put("charts", chartsMap);

        return map;
    }

    @Override
    public Map<String, Object> findByTimeBetweenForRealTimeCharts(Long startTime, Long endTime, String showCode, String stationCode, String type, String forecastManufactor) {
        long timeStep = 900000L;
        if (startTime % timeStep != 0) {
            startTime = startTime - (startTime % timeStep) + timeStep;
        }

        if (endTime % timeStep != 0) {
            endTime = endTime - (endTime % timeStep);
        }

        List<AccuracyCalculation> byTimeBetween = findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime), type, forecastManufactor);

        String accuracyRate = sysParameterService.getSysParameterAndStationCode("ACCURACY_RATE", "75,85", stationCode);

        List<AccuracyCalculation> allList = checkData(startTime, endTime, byTimeBetween, timeStep);
        //过滤数据
        exchangeValue(allList);

        allList.sort(Comparator.comparing(AccuracyCalculation::getTime));
        String[] displayCode = showCode.split(",");


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

        List<String> times = new ArrayList<>();
        map.put("times", times);

        map.put("accuracyRate", accuracyRate);

        List<String> shortTermAccuracys = new ArrayList<>();
        List<String> shortTermPassRate = new ArrayList<>();
        List<String> ultraShortTermAccuracy = new ArrayList<>();
        List<String> ultraShortTermPassRate = new ArrayList<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        for (AccuracyCalculation accuracyCalculation : allList) {
            long time = accuracyCalculation.getTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            times.add(sdf.format(new Date(time)));

            for (String s : displayCode) {

                if (s.equals("shortTermAccuracy")) {
                    String str = accuracyCalculation.getShortTermAccuracy();
                    shortTermAccuracys.add(str);
                }

                if (s.equals("shortTermPassRate")) {
                    String str = accuracyCalculation.getShortTermPass();
                    shortTermPassRate.add(str);
                }

                if (s.equals("ultraShortTermAccuracy")) {
                    String str = accuracyCalculation.getUltraShortTermAccuracy();
                    ultraShortTermAccuracy.add(str);
                }

                if (s.equals("ultraShortTermPassRate")) {
                    String str = accuracyCalculation.getUltraShortTermPass();
                    ultraShortTermPassRate.add(str);
                }
            }

        }

        for (String s : displayCode) {


            if (s.equals("shortTermAccuracy")) {

                map.put(s, shortTermAccuracys);
            }

            if (s.equals("shortTermPassRate")) {

                map.put(s, shortTermPassRate);
            }

            if (s.equals("ultraShortTermAccuracy")) {

                map.put(s, ultraShortTermAccuracy);
            }

            if (s.equals("ultraShortTermPassRate")) {

                map.put(s, ultraShortTermPassRate);
            }

        }

        return map;
    }

    @Override
    public Map<String, Object> findByTimeBetweenForRealTimeChartsDay(Long startTime, Long endTime, String showCode, String stationCode, String type, String forecastManufactor) {
        // 根据检索的时间段，查询准确率数据
        List<AccuracyCalculation> byTimeBetween = findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime), type, forecastManufactor);
        // 设定默认准确率
        String accuracyRate = sysParameterService.getSysParameterAndStationCode("ACCURACY_RATE", "75,85", stationCode);
        // 补全时间段内数据
        List<AccuracyCalculation> allList = checkDataDay(startTime, endTime, byTimeBetween);
        //过滤数据
        exchangeValueDay(allList);
        // 根据时间排序
        allList.sort(Comparator.comparing(AccuracyCalculation::getTime));

        String[] displayCode = showCode.split(",");

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

        List<String> times = new ArrayList<>();
        resultMap.put("times", times);
        resultMap.put("accuracyRate", accuracyRate);

        List<String> shortTermAccuracys = new ArrayList<>();
        List<String> shortTermPassRate = new ArrayList<>();
        List<String> ultraShortTermAccuracy = new ArrayList<>();
        List<String> ultraShortTermPassRate = new ArrayList<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 循环数据，并分别组建短期准确率、短期合格率、超短期准确率、超短期合格率
        for (AccuracyCalculation accuracyCalculation : allList) {
            times.add(sdf.format(accuracyCalculation.getTime()));
            // 循环displayCode，并组建数据
            for (String s : displayCode) {
                // 如果是短期准确率
                if (s.equals("shortTermAccuracy")) {
                    shortTermAccuracys.add(accuracyCalculation.getShortTermAccuracy());
                }
                // 如果是短期合格率
                if (s.equals("shortTermPassRate")) {
                    shortTermPassRate.add(accuracyCalculation.getShortTermPass());
                }
                // 如果是超短期准确率
                if (s.equals("ultraShortTermAccuracy")) {
                    ultraShortTermAccuracy.add(accuracyCalculation.getUltraShortTermAccuracy());
                }
                // 如果是超短期合格率
                if (s.equals("ultraShortTermPassRate")) {
                    ultraShortTermPassRate.add(accuracyCalculation.getUltraShortTermPass());
                }
            }
        }

        // 循环displayCode，并将结果放入resultMap
        for (String s : displayCode) {
            if (s.equals("shortTermAccuracy")) {
                resultMap.put(s, shortTermAccuracys);
            }
            if (s.equals("shortTermPassRate")) {
                resultMap.put(s, shortTermPassRate);
            }
            if (s.equals("ultraShortTermAccuracy")) {
                resultMap.put(s, ultraShortTermAccuracy);
            }
            if (s.equals("ultraShortTermPassRate")) {
                resultMap.put(s, ultraShortTermPassRate);
            }
        }

        return resultMap;
    }


    /**
     * 根据场站编号 开始时间 结束时间 类型查询
     *
     * @param stationCode 场站编号
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return list
     */
    public List<AccuracyCalculation> findByStationCodeAndBetweenTimeAndTypeAndForecastManufactor(String stationCode, Date startTime, Date endTime, String type, String forecastManufactor) {
        QueryWrapper<AccuracyCalculation> wrapper = new QueryWrapper<>();
        if (stationCode != null && !stationCode.equals("")) {
            wrapper.eq("station_code", stationCode);
        }
        if (forecastManufactor != null && !forecastManufactor.equals("")) {
            wrapper.eq("forecast_manufactor", forecastManufactor);
        }
        if (startTime != null && endTime != null) {
            wrapper.between("time", startTime, endTime);
        }
        if (type != null && !type.equals("")) {
            wrapper.eq("type", type);
        }
        return baseMapper.selectList(wrapper);
    }

    /**
     * 根据场站编号 开始时间 结束时间
     *
     * @param stationCode 场站编号
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return list
     */
    public List<AccuracyCalculation> findByStationCodeAndBetweenTimeAndForecastManufactor(String stationCode, Date startTime, Date endTime, String forecastManufactor) {
        QueryWrapper<AccuracyCalculation> wrapper = new QueryWrapper<>();
        if (stationCode != null && !stationCode.equals("")) {
            wrapper.eq("station_code", stationCode);
        }
        if (forecastManufactor != null && !forecastManufactor.equals("")) {
            wrapper.eq("forecast_manufactor", forecastManufactor);
        }
        if (startTime != null && endTime != null) {
            wrapper.between("time", startTime, endTime);
        }
        return baseMapper.selectList(wrapper);
    }

    /**
     * long 转 LocalDateTime
     *
     * @param timestamp
     * @return
     */
    public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 计算准确率、通过率
     *
     * @param electricField
     */
    public void calculate(ElectricField electricField) {
        String forecastManufactor = electricField.getForecastManufactor();
        String[] forecastManufactors = forecastManufactor.split(",");
        for (String f : forecastManufactors) {
            //准确率
            AccuracyCalculation accuracyPassRate = new AccuracyCalculation();
            AccuracyCalculation accuracyPassRatePoint = new AccuracyCalculation();
            // 获取相关时间
            JSONObject timeInfoJson = getTime();
            long endTime = timeInfoJson.getLong("endTime");
            // 设置结束时间
            accuracyPassRate.setTime(getDateTimeOfTimestamp(endTime));
            accuracyPassRatePoint.setTime(getDateTimeOfTimestamp(endTime));
            // 获取单点短期准确率
            String pointShortAccuracy = getAccuracyAndPass(electricField, f, "POINT_SHORT_ACCURACY");
            accuracyPassRatePoint.setShortTermAccuracy(pointShortAccuracy);
            // 获取单点超短期准确率
            String pointUltraShortAccuracy = getAccuracyAndPass(electricField, f, "POINT_ULTRA_SHORT_ACCURACY");
            accuracyPassRatePoint.setUltraShortTermAccuracy(pointUltraShortAccuracy);

            // 获取单点短期合格率
            String shortPass = getAccuracyAndPass(electricField, f, "POINT_SHORT_PASS");
            accuracyPassRatePoint.setShortTermPass(shortPass);
            // 获取单点超短期合格率
            String ultraShortPass = getAccuracyAndPass(electricField, f, "POINT_ULTRA_SHORT_PASS");
            accuracyPassRatePoint.setUltraShortTermPass(ultraShortPass);

            // 获取日短期准确率
            String dayShortAccuracy = getAccuracyAndPass(electricField, f, "DAY_SHORT_ACCURACY");
            accuracyPassRate.setShortTermAccuracy(dayShortAccuracy);
            // 获取日超短期准确率
            String dayUltraShortAccuracy = getAccuracyAndPass(electricField, f, "DAY_ULTRA_SHORT_ACCURACY");
            accuracyPassRate.setUltraShortTermAccuracy(dayUltraShortAccuracy);

            // 获取日短期合格率
            String dayShortPass = getAccuracyAndPass(electricField, f, "DAY_SHORT_PASS");
            accuracyPassRate.setShortTermPass(dayShortPass);
            // 获取日超短期合格率
            String dayUltraShortPass = getAccuracyAndPass(electricField, f, "DAY_ULTRA_SHORT_PASS");
            accuracyPassRate.setUltraShortTermPass(dayUltraShortPass);
            //设置数据类型 日/单点
            accuracyPassRate.setType("day");
            accuracyPassRate.setStationCode(electricField.getStationCode());
            accuracyPassRatePoint.setStationCode(electricField.getStationCode());
            accuracyPassRatePoint.setType("point");
            accuracyPassRate.setForecastManufactor(f);
            accuracyPassRatePoint.setForecastManufactor(f);
            // 保存单点准确率、合格率
            this.save(accuracyPassRatePoint);
            // 保存日准确率
            this.save(accuracyPassRate);
        }


    }


    /**
     * 获取准确率和通过率
     *
     * @param electricField
     * @param forecastManufactor
     * @param formulaType
     * @return
     */
    public String getAccuracyAndPass(ElectricField electricField, String forecastManufactor, String formulaType) {
        // 获取开机容量
        BigDecimal capacity = electricField.getCapacity();
        // 获取省调
        String province = "E" + electricField.getProvinceEnum().getCode();
        // 场站类型
        String electricType = "E" + electricField.getElectricFieldTypeEnum();
        String stationCode = electricField.getStationCode();
        // 获取公式
        CalculationFormula calculationFormula = calculationFormulaRepository.findByTypeAndProvince("FORMULA", formulaType, province, electricType, electricField.getStationCode());
        if (calculationFormula == null || calculationFormula.getFormula() == null) {
            return "无计算公式";
        }
        boolean doubleListFlag = false;
        // 如果公式中包含doubleList方法，则需要组装双层list
        if (calculationFormula.getFormula().indexOf("doubleList") > -1) {
            doubleListFlag = true;
        }
        // 获取相关时间
        JSONObject timeJson = getTime();
        int howLongAgo;
        // 如果是超短期，设定超短期参数，否则为短期
        if (formulaType.indexOf("ULTRA") > -1) {
            howLongAgo = Integer.parseInt(sysParameterService.getSysParameterAndStationCode("ACCURACY_CDQ_HOWLONGAGO", "16", stationCode));
        } else {
            howLongAgo = Integer.parseInt(sysParameterService.getSysParameterAndStationCode("ACCURACY_DQ_HOWLONGAGO", "1", stationCode));
        }
        // 获取计算数据
        List<CalculationInfo> calculationInfoList = getData(howLongAgo, timeJson, formulaType, doubleListFlag, stationCode, forecastManufactor);
        if (calculationInfoList.isEmpty()) {
            return "无可用数计算";
        }
        // 获取计算基础数据
        CalculateRequest calculateRequest = new CalculateRequest();
        calculateRequest.setCalculationInfoList(calculationInfoList);
        calculateRequest.setElectricCapacity(capacity);
        calculateRequest.setProvince(province);
        calculateRequest.setFormulaType(formulaType);
        calculateRequest.setElectricType(electricType);
        calculateRequest.setSign(electricField.getSign());
        calculateRequest.setStationCode(electricField.getStationCode());
        CalculateResult resultMap = accuracyPassRateCalculateService.calculate(calculateRequest);
        // 如果计算成功，从结果中获取value
        if (String.valueOf(resultMap.get(CalculateResult.CODE_TAG)).equals(CalculateResult.Type.SUCCESS.value())) {
            return String.valueOf(resultMap.get(CalculateResult.DATA_TAG));
            // 如果失败，获取失败原因
        }
        // 如果不成功，data不为空，则返回data中数据，否则返回msg
        if (resultMap.get(CalculateResult.MSG_TAG) != null && resultMap.get(CalculateResult.DATA_TAG) != null) {
            return String.valueOf(resultMap.get(CalculateResult.DATA_TAG));
        }
        return String.valueOf(resultMap.get(CalculateResult.MSG_TAG));
    }

    /**
     * 获取时间相关参数
     *
     * @return
     */
    public JSONObject getTime() {
        JSONObject result = new JSONObject();
        long[] queryTime = getQueryTimeSh();
        long endTime = queryTime[1];
        // 获取结束时间(当前的15分钟节点的前一个节点，如当前为11:16，则结束时间为11:00)
        long pointEndTime = queryTime[1] - moment15;
        // 设定短期结束时间(当前的15分钟节点的前两个节点，如当前为11:16，则结束时间为10:45)
        long pointStarTime = pointEndTime - moment15;
        // 设定超短期开始时间(当日0时0分0秒)
        long beginOfDayTime = queryTime[0];
        result.put("moment15", moment15);
        result.put("endTime", endTime);
        result.put("pointEndTime", pointEndTime);
        result.put("pointStarTime", pointStarTime);
        result.put("beginOfDayTime", beginOfDayTime);
        return result;
    }

    /**
     * 获取数据
     *
     * @param howLongAgo
     * @param timeJson
     * @param type
     * @return
     */
    public List<CalculationInfo> getData(int howLongAgo, JSONObject timeJson, String type, boolean doubleListFlag, String stationCode, String forecastManufactor) {
        List<CalculationInfo> resultList = new ArrayList<>();
        CalculationInfo calculationInfo = new CalculationInfo();

        switch (type) {
            //单点短期准确率
            case "POINT_SHORT_ACCURACY":
                // 单点短期预测功率(当前时间点最近的前一个15分钟节点的预测功率)
                ForecastPowerShortTermHis forecastPowerShortTermHis = forecastPowerShortTermHisService.findByForecastTimeAndForecastHowLongAgoAndStationCodeAndForecastManufactor(timeJson.getLong("pointEndTime"), howLongAgo, stationCode, forecastManufactor);
                if (forecastPowerShortTermHis == null) {
                    return resultList;
                }
                // 获取场站信息
                List<PowerStationStatusData> powerStationStatusDataList = powerStationStatusDataService.findByTimeBetweenAndStationCode(timeJson.getDate("pointStarTime"), timeJson.getDate("pointEndTime"), stationCode);
                if (powerStationStatusDataList.isEmpty()) {
                    return resultList;
                }
                // 按照时间倒序
                powerStationStatusDataList.sort(Comparator.comparing(PowerStationStatusData::getTime).reversed());
                // 获取时间最近的一条
                PowerStationStatusData powerStationStatusData = powerStationStatusDataList.get(0);
                // 预测功率
                BigDecimal forecastAvailableValue;
                forecastAvailableValue = forecastPowerShortTermHis.getAbleValue();
                // 存入单点相关数据
                calculationInfo.setAbleValue(powerStationStatusData.getAbleValue());
                calculationInfo.setRealValue(powerStationStatusData.getRealValue());
                calculationInfo.setTheoryValue(powerStationStatusData.getTheoryValue());
                calculationInfo.setOpenCapacity(powerStationStatusData.getOpenCapacity());
                calculationInfo.setCapacity(powerStationStatusData.getCapacity());
                // 预测信息
                calculationInfo.setForecastAbleValue(forecastAvailableValue);
                calculationInfo.setForecastTheoryValue(forecastPowerShortTermHis.getTheoryValue());
                calculationInfo.setForecastCapacity(forecastPowerShortTermHis.getCapacity());
                calculationInfo.setForecastSuCapacity(forecastPowerShortTermHis.getSuCapacity());
                resultList.add(calculationInfo);
                break;
            // 单点短期合格率
            case "POINT_SHORT_PASS":
                resultList = loopMatching(timeJson.getLong("pointStarTime"), timeJson.getLong("pointEndTime"), "short", howLongAgo, doubleListFlag, stationCode, forecastManufactor);
                break;
            //点单超短期准确率、单点超短期合格率
            case "POINT_ULTRA_SHORT_ACCURACY":
            case "POINT_ULTRA_SHORT_PASS":
                resultList = loopMatching(timeJson.getLong("beginOfDayTime"), timeJson.getLong("pointEndTime"), "ultraShort", howLongAgo, doubleListFlag, stationCode, forecastManufactor);
                break;
            case "DAY_ULTRA_SHORT_ACCURACY":
            case "DAY_ULTRA_SHORT_PASS":
                resultList = loopMatching(timeJson.getLong("beginOfDayTime"), timeJson.getLong("endTime"), "ultraShort", howLongAgo, doubleListFlag, stationCode, forecastManufactor);
                break;
            // 日短期准确率、日短期合格率数据
            case "DAY_SHORT_ACCURACY":
            case "DAY_SHORT_PASS":
                resultList = loopMatching(timeJson.getLong("beginOfDayTime"), timeJson.getLong("endTime"), "short", howLongAgo, doubleListFlag, stationCode, forecastManufactor);
                break;
            default:
                break;
        }
        return resultList;
    }

    /**
     * 循环匹配每个时间的实际功率和预测功率
     *
     * @param startTime
     * @param endTime
     * @param type
     * @return
     */
    public List<CalculationInfo> loopMatching(long startTime, long endTime, String type, Integer howLongAgo, boolean doubleListFlag, String stationCode, String forecastManufactor) {
        ElectricField electricField = electricFieldService.findByStationCode(stationCode);
        //解析中目前不带 开机和装机容量，无法计算准确率，先用场站容量代替
        BigDecimal cap = electricField.getCapacity();
        List<CalculationInfo> resultList = new ArrayList<>();
        // 获取实际功率
        List<PowerStationStatusData> powerStationStatusDataList = powerStationStatusDataService.findByTimeBetweenAndStationCode(new Date(startTime), new Date(endTime), stationCode);
        // 短期预测功率
        List<ForecastPowerShortTermHis> forecastShortList = forecastPowerShortTermHisService.findByForecastTimeBetweenAndForecastHowLongAgoAndStationCodeAndForecastManufactor(startTime, endTime, howLongAgo, stationCode, forecastManufactor);
        // 超短期预测功率
        List<ForecastPowerUltraShortTermHis> forecastUltraShortList = forecastPowerUltraShortTermHisService.findByStationCodeAndStartTimeAndEndTimeAndHowLongAgoAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime), howLongAgo, forecastManufactor);
        // 从开始时间，每隔15分钟，一直循环到当前时间
        for (long stepTime = startTime; stepTime <= endTime; stepTime += moment15) {
            long finalTime = stepTime;
            // 获取该时间点场站功率
            List<PowerStationStatusData> pFilter = powerStationStatusDataList.stream().filter((p) -> p.getTime().compareTo(getDateTimeOfTimestamp(finalTime)) == 0).collect(Collectors.toList());
            // 组装数据
            CalculationInfo calculationInfo = new CalculationInfo();
            // 如果是短期数据
            if ("short".equals(type)) {
                List<ForecastPowerShortTermHis> shortFilter = forecastShortList.stream().filter(u -> u.getForecastTime().getTime()==finalTime).collect(Collectors.toList());
                // 如果短期预测功率不为空且站场功率不为空
                if (!shortFilter.isEmpty() && !pFilter.isEmpty()) {
                    // 短期预测功率
                    calculationInfo.setTime(finalTime);
                    calculationInfo.setForecastAbleValue(shortFilter.get(0).getAbleValue());
                    calculationInfo.setForecastTheoryValue(shortFilter.get(0).getTheoryValue());
                    calculationInfo.setForecastCapacity(cap);
                    calculationInfo.setForecastSuCapacity(cap);
                    //实际
                    calculationInfo.setCapacity(cap);
                    calculationInfo.setOpenCapacity(cap);
                    calculationInfo.setAbleValue(pFilter.get(0).getAbleValue());
                    calculationInfo.setRealValue(pFilter.get(0).getRealValue());
                    calculationInfo.setTheoryValue(pFilter.get(0).getTheoryValue());
                }
                // 如果是超短期数据
            } else if ("ultraShort".equals(type)) {
                // 如果公式中需要双层list，则将每个点的16个数据都放入list中
                if (doubleListFlag) {
                    List<ForecastPowerUltraShortTermHis> ultraList = forecastPowerUltraShortTermHisService.findByForecastTimeAndStationCode(finalTime, stationCode);
                    List<PowerStationStatusData> powerStationStatusDataFilter = powerStationStatusDataList.stream().filter(p -> p.getTime().compareTo(getDateTimeOfTimestamp(finalTime)) == 0).collect(Collectors.toList());
                    if (!ultraList.isEmpty() && !powerStationStatusDataFilter.isEmpty()) {
                        for (ForecastPowerUltraShortTermHis ultraShort : ultraList) {
                            calculationInfo = new CalculationInfo();
                            // 设置实际功率、可用功率信息
                            calculationInfo.setCapacity(cap);
                            calculationInfo.setOpenCapacity(cap);
                            calculationInfo.setAbleValue(pFilter.get(0).getAbleValue());
                            calculationInfo.setRealValue(pFilter.get(0).getRealValue());
                            calculationInfo.setTheoryValue(pFilter.get(0).getTheoryValue());
                            // 设置超短期信息
                            calculationInfo.setTime(finalTime);
                            calculationInfo.setForecastSuCapacity(cap);
                            calculationInfo.setForecastAbleValue(ultraShort.getAbleValue());
                            calculationInfo.setForecastTheoryValue(ultraShort.getTheoryValue());
                            calculationInfo.setForecastCapacity(cap);
                            calculationInfo.setGenTime(ultraShort.getGenDate());
                        }
                        continue;
                    }
                } else {
                    // 获取该时间点超短期预测功率
                    List<ForecastPowerUltraShortTermHis> ultraFilter = forecastUltraShortList.stream().filter(u -> u.getForecastTime().getTime()==finalTime).collect(Collectors.toList());
                    // 如果超短期预测功率不为空且站场功率不为空
                    if (!ultraFilter.isEmpty()) {
                        // 超短期预测功率
                        calculationInfo.setForecastSuCapacity(cap);
                        calculationInfo.setForecastAbleValue(ultraFilter.get(0).getAbleValue());
                        calculationInfo.setForecastTheoryValue(ultraFilter.get(0).getTheoryValue());
                        calculationInfo.setForecastCapacity(cap);
                    }
                }
            }
            // 如果站场信息不为空
            if (!pFilter.isEmpty()) {
                // 实际功率、可用功率
                calculationInfo.setAbleValue(pFilter.get(0).getAbleValue());
                calculationInfo.setRealValue(pFilter.get(0).getRealValue());
                calculationInfo.setTheoryValue(pFilter.get(0).getTheoryValue());
                calculationInfo.setOpenCapacity(cap);
                calculationInfo.setCapacity(cap);
                calculationInfo.setTime(finalTime);
            }
            // 预测功率或实际功率为空的时候，不放入result中
            if (calculationInfo.getRealValue() != null && calculationInfo.getAbleValue() != null && calculationInfo.getForecastAbleValue() != null) {
                resultList.add(calculationInfo);
            }
        }
        return resultList;
    }


    static long[] getQueryTimeSh() {
        long[] result = new long[2];
        long startTime = DateUtil.beginOfDay(DateTime.now()).getTime();
        long nowTime = DateTime.now().getTime();
        long moment15 = 900000L;
        BigDecimal nowTimeBig = new BigDecimal(String.valueOf(nowTime));
        BigDecimal moment15Big = new BigDecimal(String.valueOf(moment15));
        BigDecimal queryTimeBig = nowTimeBig.divideAndRemainder(moment15Big)[0].multiply(moment15Big);
        long endTime = queryTimeBig.longValue();
        result[0] = startTime;
        result[1] = endTime;
        return result;
    }
}
