package com.cpp.web.service.accuracy.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.system.service.ISysDictDataService;
import com.cpp.web.domain.accuracy.AccuracyPassRate;
import com.cpp.web.domain.enums.DataSourcesEnum;
import com.cpp.web.domain.enums.ForecastTypeEnum;
import com.cpp.web.mapper.accuracy.AccuracyPassRateMapper;
import com.cpp.web.service.accuracy.AccuracyPassRateService;
import com.cpp.web.utils.StartAndEndMonthUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * idp_forecast_power_short_term
 *
 * @author tl
 * @date 2024-09-23 15:28:33
 */
@Service
public class AccuracyPassRateServiceImpl extends ServiceImpl<AccuracyPassRateMapper, AccuracyPassRate> implements AccuracyPassRateService {

    @Autowired
    private ISysDictDataService dictDataService;
    @Override
    public List<AccuracyPassRate> findByTimeBetweenAndForecastTypeAndDataSourcesAndAgoAndForecastModelAndStationCode(Date startTime, Date endTime, ForecastTypeEnum forecastType, DataSourcesEnum dataSources, Integer ago, String forecastModel, String stationCode) {
        QueryWrapper<AccuracyPassRate> wrapper = new QueryWrapper<>();
        if (stationCode != null && !stationCode.equals("")) {
            wrapper.eq("station_code", stationCode);
        }
        if (startTime != null && endTime != null) {
            wrapper.between("time", startTime, endTime);
        }
        if (forecastType != null && !forecastType.equals("")) {
            wrapper.eq("forecast_type", forecastType);
        }
        if (dataSources != null && !dataSources.equals("")) {
            wrapper.eq("data_sources", dataSources);
        }
        if (forecastModel != null && !forecastModel.equals("")) {
            wrapper.eq("forecast_model", forecastModel);
        }
        if (ago != null && !ago.equals("")) {
            wrapper.eq("forecast_how_long_ago", ago);
        }
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<AccuracyPassRate> findByTimeBetweenAndStationCode(Date startTime, Date endTime, String stationCode) {
        QueryWrapper<AccuracyPassRate> wrapper = new QueryWrapper<>();
        if (null != startTime && null != endTime){
            wrapper.between("time",startTime,endTime);
        }
        if (null != stationCode && !"".equals(stationCode)){
            wrapper.eq("station_code",stationCode);
        }
        wrapper.eq("data_sources","E2");
        wrapper.eq("forecast_how_long_ago",1);
        wrapper.eq("forecast_type","dq");
        return list(wrapper);
    }

    @Override
    public Map<String, Double> findByMonthBetweenAndForecastTypeAndStationCode(Long startTime, Long endTime, ForecastTypeEnum forecastType, DataSourcesEnum dataSources,String stationCode) {

        QueryWrapper<AccuracyPassRate> wrapper = new QueryWrapper<>();
        if (stationCode != null && !stationCode.equals("")) {
            wrapper.eq("station_code", stationCode);
        }
        if (startTime != null && endTime != null) {
            wrapper.between("time", new Date(StartAndEndMonthUtil.getBeginAndEndMonth(startTime,1)), new Date(StartAndEndMonthUtil.getBeginAndEndMonth(endTime,2)));
        }
        if (forecastType != null && !forecastType.equals("")) {
            wrapper.eq("forecast_type", forecastType);
        }
        if (dataSources != null && !dataSources.equals("")) {
            wrapper.eq("data_sources", dataSources);
        }
        List<AccuracyPassRate> accuracyPassRateList = baseMapper.selectList(wrapper);

        Map<String, Double> sortMap = new TreeMap<>();
        if (null != accuracyPassRateList && accuracyPassRateList.size() > 0) {
            accuracyPassRateList = accuracyPassRateList.stream().filter(f -> !"无可用数据计算".equals(f.getAccuracy()) && !"无计算公式".equals(f.getAccuracy())).collect(Collectors.toList());

            Function<String, Double> stringToDouble = s -> {
                String numberStr = s.replace("%", "");
                return Double.parseDouble(numberStr);
            };
            Map<String, Double> averageByCategory = accuracyPassRateList.stream()
                    .filter(apr -> apr.getForecastModel()!=null)
                    .collect(Collectors.groupingBy(
                            AccuracyPassRate::getForecastModel,
                            Collectors.averagingDouble(apr -> stringToDouble.apply(apr.getAccuracy()))
                    ));
            Map<String, Double> updatedAverageByCategory = averageByCategory.entrySet().stream()
                    .collect(Collectors.toMap(
                            entry->dictDataService.selectDictLabel("forecast_model",entry.getKey())==null?entry.getKey():dictDataService.selectDictLabel("forecast_model",entry.getKey()),
                            entry->entry.getValue()
                    ));
            sortMap = new TreeMap<>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return updatedAverageByCategory.get(o2).compareTo(updatedAverageByCategory.get(o1));
                }
            });

            sortMap.putAll(updatedAverageByCategory);

        }
        return sortMap;
    }

    @Override
    public List<Map<String,String>> finfBySingleMonthBetweenAndForecastTypeAndStationCode(Long startTime, Long endTime, ForecastTypeEnum forecastType, DataSourcesEnum dataSources, String stationCode,String stationName,String uploadDataSources) {
        List<Map<String,String>> list = new ArrayList<>();
        List<long[]> longs = StartAndEndMonthUtil.singleMonth(startTime, endTime);
        Collections.reverse(longs);

        for (long[] aLong : longs) {
            QueryWrapper<AccuracyPassRate> wrapper = new QueryWrapper<>();
            QueryWrapper<AccuracyPassRate> wrapper2 = new QueryWrapper<>();
            if (stationCode != null && !stationCode.equals("")) {
                wrapper.eq("station_code", stationCode);
                wrapper2.eq("station_code", stationCode);
            }

            if (forecastType != null && !forecastType.equals("")) {
                wrapper.eq("forecast_type", forecastType);
                wrapper2.eq("forecast_type", forecastType);
            }
            if (dataSources != null && !dataSources.equals("")) {
                wrapper.eq("data_sources", dataSources);
                wrapper2.eq("data_sources", uploadDataSources);
            }
            int count = 0;
            if (startTime != null && endTime != null) {
                wrapper.between("time", new Date(aLong[0]), new Date(aLong[1]));
                wrapper.orderByDesc("time");
                wrapper2.between("time", new Date(aLong[0]), new Date(aLong[1]));
                wrapper2.orderByDesc("time");
            }
            List<AccuracyPassRate> accuracyPassRateList = baseMapper.selectList(wrapper);

            List<AccuracyPassRate> accuracyPassRateList2 = baseMapper.selectList(wrapper2);

            accuracyPassRateList = accuracyPassRateList.stream().filter(f -> !"无可用数据计算".equals(f.getAccuracy()) && !"无计算公式".equals(f.getAccuracy())).collect(Collectors.toList());
            accuracyPassRateList2 = accuracyPassRateList2.stream().filter(f -> !"无可用数据计算".equals(f.getAccuracy()) && !"无计算公式".equals(f.getAccuracy())).collect(Collectors.toList());
            BigDecimal collect = BigDecimal.ZERO;
            if (accuracyPassRateList2.size()>0){
                collect = BigDecimal.valueOf(accuracyPassRateList2.stream().collect(Collectors.summingDouble(s -> Double.valueOf(s.getAccuracy().replace("%", ""))))/accuracyPassRateList2.size()).setScale(2, RoundingMode.HALF_UP);
            }
            Function<String, Double> stringToDouble = s -> {
                String numberStr = s.replace("%", "");
                return Double.parseDouble(numberStr);
            };
            Map<String, Double> averageByCategory = accuracyPassRateList.stream()
                    .filter(apr -> apr.getForecastModel()!=null)
                    .collect(Collectors.groupingBy(
                            AccuracyPassRate::getForecastModel,
                            Collectors.averagingDouble(apr -> stringToDouble.apply(apr.getAccuracy()))
                    ));

            Map<String, Double> sortMap = new TreeMap<>();
            sortMap = new TreeMap<>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return averageByCategory.get(o2).compareTo(averageByCategory.get(o1));
                }
            });
            sortMap.putAll(averageByCategory);

            for (Map.Entry<String, Double> entry : sortMap.entrySet()) {
                Map<String,String> map = new HashMap<>();
                map.put("station",stationName);
                map.put("month",new SimpleDateFormat("yyyy-MM").format(new Date(aLong[0])));
                map.put("preModels",dictDataService.selectDictLabel("forecast_model",entry.getKey())==null?entry.getKey():dictDataService.selectDictLabel("forecast_model",entry.getKey()));
                map.put("shortAccuracy",BigDecimal.valueOf(entry.getValue()).setScale(2, RoundingMode.HALF_UP).toString());
                map.put("uploadShortAccuracy",collect.toString());
                map.put("accuracyRanking",String.valueOf(++count));
                list.add(map);
            }

        }
        return list;
    }
}
