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

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.common.utils.DateUtils;
import com.cpp.web.domain.BaseCppEntity;
import com.cpp.web.domain.accuracy.AccuracyPassRate;
import com.cpp.web.domain.cloud.ForecastPowerShortTermCloud;
import com.cpp.web.domain.enums.DataSourcesEnum;
import com.cpp.web.domain.powerGeneration.DayPowerGeneration;
import com.cpp.web.domain.station.ForecastPowerShortTermStation;
import com.cpp.web.mapper.powerGeneration.DayPowerGenerationMapper;
import com.cpp.web.service.accuracy.AccuracyPassRateService;
import com.cpp.web.service.cloud.ForecastPowerShortTermCloudService;
import com.cpp.web.service.powerGeneation.DayPowerGenerationService;
import com.cpp.web.service.station.ForecastPowerShortTermStationService;
import com.cpp.web.utils.DateTimeUtil;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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;

/**
 * cpp_day_power_generation
 *
 * @author fxy
 * @date 2024-10-14 9:47:33
 */
@Service
@RequiredArgsConstructor
public class DayPowerGenerationServiceImpl extends ServiceImpl<DayPowerGenerationMapper, DayPowerGeneration> implements DayPowerGenerationService {

    private final DayPowerGenerationMapper dayPowerGenerationMapper;

    private final ForecastPowerShortTermCloudService forecastPowerShortTermCloudService;

    private final ForecastPowerShortTermStationService forecastPowerShortTermStationService;

    private final AccuracyPassRateService accuracyPassRateService;

    private final String dateFormat = new SimpleDateFormat("yyyy-MM-dd").format(new Date());

    @Override
    public DayPowerGeneration findByStationCodeAndGenDate(String stationCode, Date genDate) {
        QueryWrapper<DayPowerGeneration> wrapper = new QueryWrapper<>();
        if (null != stationCode && !"".equals(stationCode)) {
            wrapper.eq("station_code", stationCode);
        }
        if (null != genDate) {
            wrapper.eq("gen_date", genDate);
        }
        return dayPowerGenerationMapper.selectOne(wrapper);
    }

    /**
     * 发电量业务
     *
     * @param stationCode
     */
    @Override
    public void generatePower(String stationCode) {

        Date accuracyStartTime = DateTimeUtil.getDayStartTime(System.currentTimeMillis() - 30 * 24 * 60 * 60 * 1000L);
        Date accuracyEndTime = DateTimeUtil.getDayStartTime(System.currentTimeMillis()  - 24 * 60 * 60 * 1000L);


        String forecastModel = "";

        // 查询近一个月内平均准确率高的预测模型
        List<AccuracyPassRate> accuracyPassRateList = accuracyPassRateService.findByTimeBetweenAndStationCode(accuracyStartTime, accuracyEndTime, stationCode);

        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()
                    .collect(Collectors.groupingBy(
                            AccuracyPassRate::getForecastModel,
                            Collectors.averagingDouble(apr -> stringToDouble.apply(apr.getAccuracy()))
                    ));
            // 找出平均值最大的那一组
            Optional<Map.Entry<String, Double>> maxAverageEntry = averageByCategory.entrySet().stream().max(Map.Entry.comparingByValue());
            // 获取模型
            forecastModel = maxAverageEntry.get().getKey();
        }

        Date startTime = DateTimeUtil.getDayStartTime(System.currentTimeMillis() + 24 * 60 * 60 * 1000L);

        Date endTime = DateTimeUtil.getDayLastTime(startTime.getTime() + 10 * 24 * 60 * 60 * 1000L - 1);

        List<DayPowerGeneration> dayPowerGenerationList = findByGenDate(dateFormat, stationCode);

        if (dayPowerGenerationList.size() > 0) {
            return;
        }
        // 云端预测
        List<ForecastPowerShortTermCloud> forecastPowerShortTermCloudList = forecastPowerShortTermCloudService.findByForecastTimeBetweenAndStationCode(startTime, endTime, stationCode,"".equals(forecastModel)?"JY":forecastModel);
        // 站端预测
        List<ForecastPowerShortTermStation> forecastPowerShortTermStationList = forecastPowerShortTermStationService.findByForecastTimeBetweenAndStationCode(startTime, endTime, stationCode);

        List<DayPowerGeneration> ydList = calculator(forecastPowerShortTermCloudList, "yd", startTime, stationCode);
        List<DayPowerGeneration> zdList = calculator(forecastPowerShortTermStationList, "zd", startTime, stationCode);

        this.saveBatch(ydList);
        this.saveBatch(zdList);
    }

    @Override
    public List<DayPowerGeneration> findByStationCodeAndGenDateAndPredictionDataSource(String stationCode, String genDate, String predictionDataSource) {
        QueryWrapper<DayPowerGeneration> wrapper = new QueryWrapper<>();
        if (null != stationCode && !"".equals(stationCode)) {
            wrapper.eq("station_code", stationCode);
        }
        if (null != genDate && !"".equals(genDate)) {
            wrapper.eq("gen_date", genDate);
        }
        if (null != predictionDataSource && !"".equals(predictionDataSource)) {
            wrapper.eq("prediction_data_source", predictionDataSource);
        }
        return list(wrapper);
    }


    /**
     * 计算发电量
     *
     * @param list
     * @param type
     * @param startTime
     * @param stationCode
     * @return
     */

    public List<DayPowerGeneration> calculator(List<? extends BaseCppEntity> list, String type, Date startTime, String stationCode) {
        List<DayPowerGeneration> resultList = new ArrayList<>();
        BigDecimal radio = new BigDecimal(0.025);
        BigDecimal sumValue;
        String[] datas;
        Date date;
        String dateStr;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 1; i <= 10; i++) {
            DayPowerGeneration dayPowerGeneration = new DayPowerGeneration();
            sumValue = BigDecimal.ZERO;
            date = DateUtils.addDays(startTime, i - 1);
            dateStr = simpleDateFormat.format(date);
            datas = findSendData(startTime.getTime() + 1000L * 60 * 60 * 24 * (i - 1), startTime.getTime() + 1000L * 60 * 60 * 24 * i - 1000L * 60 * 15, list);
            if (datas.length > 0) {
                BigDecimal value;
                for (int j = 0; j < datas.length; j++) {
                    String s = datas[j];
                    if (StrUtil.isNotEmpty(s)) {
                        value = new BigDecimal(s).multiply(radio).setScale(2, RoundingMode.HALF_UP);
                        sumValue = sumValue.add(value);
                    }
                }
            }
            dayPowerGeneration.setGenDate(simpleDateFormat.format(new Date()));
            dayPowerGeneration.setForecastPowerGeneration(sumValue);
            dayPowerGeneration.setForecastHowLongAgo(i);
            dayPowerGeneration.setTime(dateStr);
            dayPowerGeneration.setStationCode(stationCode);
            if (type.equals("yd")) {
                dayPowerGeneration.setPredictionDataSource("云端下发");
            } else {
                dayPowerGeneration.setPredictionDataSource("站端上传");
            }
            resultList.add(dayPowerGeneration);
        }
        return resultList;
    }

    /**
     * 查询回传数据
     *
     * @param stTime 开始时间
     * @param eTime  结束时间
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public String[] findSendData(Long stTime, Long eTime, List<? extends BaseCppEntity> list) {
        String[] datas = new String[0];
        List<ForecastPowerShortTermCloud> forecastPowerShortTermCloudList = new ArrayList<>();
        List<ForecastPowerShortTermStation> forecastPowerShortTermStationList = new ArrayList<>();
        for (BaseCppEntity entity : list) {
            if (entity instanceof ForecastPowerShortTermCloud) {
                forecastPowerShortTermCloudList.add((ForecastPowerShortTermCloud) entity);
            } else if (entity instanceof ForecastPowerShortTermStation) {
                forecastPowerShortTermStationList.add((ForecastPowerShortTermStation) entity);
            }
        }
        if (forecastPowerShortTermCloudList.size() > 0) {
            List<ForecastPowerShortTermCloud> collectList = forecastPowerShortTermCloudList.stream().filter(s -> s.getTime().getTime() >= stTime && s.getTime().getTime() <= eTime).collect(Collectors.toList());
            if (null != forecastPowerShortTermCloudList && forecastPowerShortTermCloudList.size() > 0) {
                datas = new String[collectList.size()];
                int index = 0;
                for (ForecastPowerShortTermCloud f : collectList) {
                    datas[index] = String.valueOf(f.getFpValue());
                    index++;
                }
            }
        } else {
            List<ForecastPowerShortTermStation> collectList = forecastPowerShortTermStationList.stream().filter(s -> s.getTime().getTime() >= stTime && s.getTime().getTime() <= eTime).collect(Collectors.toList());
            if (null != forecastPowerShortTermStationList && forecastPowerShortTermStationList.size() > 0) {
                datas = new String[collectList.size()];
                int index = 0;
                for (ForecastPowerShortTermStation f : collectList) {
                    datas[index] = String.valueOf(f.getFpValue());
                    index++;
                }
            }
        }

        return datas;
    }

    public List<DayPowerGeneration> findByGenDate(String genDate, String stationCode) {
        QueryWrapper<DayPowerGeneration> wrapper = new QueryWrapper<>();
        if (null != genDate && !"".equals(genDate)) {
            wrapper.eq("gen_date", genDate);
        }
        if (null != stationCode && !"".equals(stationCode)) {
            wrapper.eq("station_code", stationCode);
        }
        return list(wrapper);
    }

}




