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

import com.cpp.common.utils.spring.SpringUtils;
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.enums.ForecastTypeEnum;
import com.cpp.web.domain.station.ElectricField;
import com.cpp.web.domain.station.PowerStationStatusData;
import com.cpp.web.service.accuracy.CalculateInterface;
import com.cpp.web.service.cloud.ForecastPowerShortTermCloudService;
import com.syjy.calculate.entity.CalculateRequest;
import com.syjy.calculate.entity.CalculateResult;
import com.syjy.calculate.entity.CalculationInfo;
import com.syjy.calculate.service.AccuracyPassRateCalculateService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

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

/**
 * 计算中心测短期预测分析结果
 */
@Service
@RequiredArgsConstructor
public class CalculateForecastPowerShortTermCloudImpl implements CalculateInterface {
    private final ForecastPowerShortTermCloudService forecastPowerShortTermCloudService;


    @Override
    public List<AccuracyPassRate> calc(Date startTime, Date endTime, List<PowerStationStatusData> powerStationStatusDataList, List<ElectricField> electricFieldList, List<String> formulaTypes, String province) {

        List<AccuracyPassRate> accuracyPassRates = new ArrayList<>();

        List<ForecastPowerShortTermCloud> forecastPowerShortTermCloudList = forecastPowerShortTermCloudService.findByForecastTimeBetweenAndHowLongAgo(startTime, endTime, 1);

        Map<Integer, List<ForecastPowerShortTermCloud>> agoListMap = forecastPowerShortTermCloudList.stream().collect(Collectors.groupingBy(ForecastPowerShortTermCloud::getForecastHowLongAgo, Collectors.toList()));

        for (int ago = 1; ago < 11; ago++) {

            if (agoListMap.containsKey(ago)) {
                Map<String, List<ForecastPowerShortTermCloud>> listForecastModelMap = agoListMap.get(ago).stream().collect(Collectors.groupingBy(ForecastPowerShortTermCloud::getForecastModel, Collectors.toList()));

                for (ElectricField electricField : electricFieldList) {
                    // 获取装机容量
                    BigDecimal capacity = electricField.getCapacity();
                    // 获取场站编码
                    String stationCode = electricField.getStationCode();
                    // 场站类型
                    String electricType = electricField.getElectricFieldTypeEnum();

                    for (String forecastModel : listForecastModelMap.keySet()) {
                        AccuracyPassRate accuracyPassRate = new AccuracyPassRate();
                        accuracyPassRate.setTime(startTime);
                        accuracyPassRate.setDataSources(DataSourcesEnum.E2);
                        accuracyPassRate.setForecastModel(forecastModel);
                        accuracyPassRate.setForecastType(ForecastTypeEnum.dq);
                        accuracyPassRate.setForecastHowLongAgo(ago);
                        accuracyPassRate.setStationCode(electricField.getStationCode());

                        // 获取实际功率
                        Map<Date, List<ForecastPowerShortTermCloud>> dateForecastListMap = forecastPowerShortTermCloudList.stream().filter(p -> p.getStationCode().equals(stationCode)).collect(Collectors.groupingBy(ForecastPowerShortTermCloud::getTime, Collectors.toList()));
                        // 短期预测功率
                        Map<Date, List<PowerStationStatusData>> datePowerListMap = powerStationStatusDataList.stream().filter(f -> f.getStationCode().equals(stationCode)).collect(Collectors.groupingBy(PowerStationStatusData::getTime, Collectors.toList()));
                        //解析中目前不带 开机和装机容量，无法计算准确率，先用场站容量代替
                        BigDecimal cap = electricField.getCapacity();

                        if (formulaTypes.contains("DAY_SHORT_ACCURACY")) {//准确率计算
                            List<CalculationInfo> calculationInfoList = new ArrayList<>();
                            // 从开始时间，每隔15分钟，一直循环到当前时间
                            for (long stepTime = startTime.getTime(); stepTime <= endTime.getTime(); stepTime += 900000L) {
                                Date finalTime = new Date(stepTime);
                                // 组装数据
                                CalculationInfo calculationInfo = new CalculationInfo();
                                // 如果短期预测功率不为空且站场功率不为空
                                if (dateForecastListMap.containsKey(finalTime) && datePowerListMap.containsKey(finalTime)) {

                                    PowerStationStatusData powerStationStatusData = datePowerListMap.get(finalTime).get(0);
                                    //限电时不参与考核，抛去
                                    if (!powerStationStatusData.getPowerRationing().equals(1)) {
                                        ForecastPowerShortTermCloud forecastPowerShortTermCloud = dateForecastListMap.get(finalTime).get(0);
                                        // 短期预测功率
                                        calculationInfo.setTime(stepTime);
                                        calculationInfo.setForecastAbleValue(forecastPowerShortTermCloud.getFpValue());
                                        calculationInfo.setForecastTheoryValue(forecastPowerShortTermCloud.getFpValue());
                                        calculationInfo.setForecastCapacity(cap);
                                        calculationInfo.setForecastSuCapacity(cap);


                                        //实际
                                        calculationInfo.setCapacity(cap);
                                        calculationInfo.setOpenCapacity(cap);
                                        calculationInfo.setAbleValue(powerStationStatusData.getAbleValue());
                                        calculationInfo.setRealValue(powerStationStatusData.getRealValue());
                                        calculationInfo.setTheoryValue(powerStationStatusData.getTheoryValue());
                                    }

                                }

                                // 预测功率或实际功率为空的时候，不放入result中
                                if (calculationInfo.getRealValue() != null && calculationInfo.getAbleValue() != null && calculationInfo.getForecastAbleValue() != null) {
                                    calculationInfoList.add(calculationInfo);
                                }
                            }


                            if (calculationInfoList == null || calculationInfoList.size() == 0) {
                                accuracyPassRate.setAccuracy("无可用数据计算");
                            } else {
                                // 获取计算基础数据
                                CalculateRequest calculateRequest = new CalculateRequest();
                                calculateRequest.setCalculationInfoList(calculationInfoList);
                                calculateRequest.setElectricCapacity(capacity);
                                calculateRequest.setProvince(province);
                                calculateRequest.setStationCode(stationCode);
                                calculateRequest.setFormulaType("DAY_SHORT_ACCURACY");
                                calculateRequest.setElectricType(electricType);
                                calculateRequest.setSign(electricField.getStationCode());
                                calculateRequest.setStationStatus("无");
                                calculateRequest.setStationCode(electricField.getStationCode());
                                CalculateResult resultMap = SpringUtils.getBean(AccuracyPassRateCalculateService.class).calculate(calculateRequest);
                                // 如果计算成功，从结果中获取value
                                if (String.valueOf(resultMap.get(CalculateResult.CODE_TAG)).
                                        equals(CalculateResult.Type.SUCCESS.value())) {
                                    accuracyPassRate.setAccuracy(String.valueOf(resultMap.get(CalculateResult.DATA_TAG)));
                                }
                                // 如果不成功，data不为空，则返回data中数据，否则返回msg
                                if (resultMap.get(CalculateResult.DATA_TAG) != null) {
                                    accuracyPassRate.setAccuracy(String.valueOf(resultMap.get(CalculateResult.DATA_TAG)));
                                }
                            }

                        }
                        if (formulaTypes.contains("POINT_SHORT_ACCURACY")) {//单点偏差计算
                            List<BigDecimal> values = new ArrayList<>();
                            for (long stepTime = startTime.getTime(); stepTime <= endTime.getTime(); stepTime += 900000L) {
                                Date finalTime = new Date(stepTime);

                                if (dateForecastListMap.containsKey(finalTime) && datePowerListMap.containsKey(finalTime)) {
                                    PowerStationStatusData powerStationStatusData = datePowerListMap.get(finalTime).get(0);
                                    if (!powerStationStatusData.getPowerRationing().equals(1)) {
                                        ForecastPowerShortTermCloud forecastPowerShortTermCloud = dateForecastListMap.get(finalTime).get(0);
                                        BigDecimal subtractAbs = powerStationStatusData.getRealValue().subtract(forecastPowerShortTermCloud.getFpValue()).abs();
                                        BigDecimal value = subtractAbs.divide(electricField.getCapacity(), 4, BigDecimal.ROUND_DOWN);
                                        values.add(value);
                                    }
                                }

                            }

                            if (values.size() > 0) {
                                Double value = values.stream().mapToDouble(v -> v.doubleValue()).average().getAsDouble();
                                accuracyPassRate.setDeviationSum(String.format("%.2f", value * 100) + "%");
                            } else {
                                accuracyPassRate.setDeviationSum("无可用数据计算");
                            }
                        }
                        accuracyPassRates.add(accuracyPassRate);
                    }
                }
            }
        }

        return accuracyPassRates;
    }


    @Override
    public List<String> calculationTypes() {
        return Arrays.asList("DAY_SHORT_ACCURACY", "POINT_SHORT_ACCURACY");
    }


}

