package com.jiayue.ipp.idp.api;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jiayue.ipp.common.data.entity.ForecastPowerShortTerm;
import com.jiayue.ipp.common.data.entity.ForecastPowerUltraShortTerm;
import com.jiayue.ipp.common.data.entity.ForecastPowerUltraShortTermHis;
import com.jiayue.ipp.common.data.entity.PowerStationStatusData;
import com.jiayue.ipp.idp.service.*;
import com.jiayue.ipp.idp.util.DateMomentUtil;
import com.jiayue.ipp.idp.util.DateTimeUtil;
import com.jiayue.ipp.idp.util.JsonBeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 超短期数据
 *
 * @Author: tl
 * @Date: 2023/3/28 0028 13:16
 */
@Service
@Slf4j
@AllArgsConstructor
public class CallForecastPowerUltraShortTermApi {

    ForecastPowerUltraShortTermService forecastPowerUltraShortTermService;
    ForecastPowerUltraShortTermHisService forecastPowerUltraShortTermHisService;
    ForecastPowerShortTermService forecastPowerShortTermService;

    PowerStationStatusDataService powerStationStatusDataService;

    ElectricFieldService electricFieldService;

    SysParameterService sysParameterService;


//    @Scheduled(fixedRate = 60000l)
    public void obiainForecastPowerUltraShortTerm() {

        long now = DateTimeUtil.getMomentTimeFor15Minute(System.currentTimeMillis()).getTime() + 15 * 60 * 1000l;

        long startTime = now - 240 * 60 * 1000l;
        electricFieldService.list().forEach(e -> {

            String stationCode = e.getStationCode();
            try {
                //超短期数据
                List<ForecastPowerShortTerm> fpustList = forecastPowerShortTermService.findByStationCodeAndStartTimeAndEndTime(stationCode, new Date(now), new Date(now + 16 * 15 * 60000));

                //实际功率数据
                List<PowerStationStatusData> pssdList = powerStationStatusDataService.findByStationCodeAndStartTimeAndEndTime(stationCode, new Date(startTime), new Date(now));

                List<ForecastPowerUltraShortTerm> forecastPowerUltraShortTermList = getForecastPowerUltraShortTerm(fpustList, pssdList, now, e.getCapacity(), stationCode);

                forecastPowerUltraShortTermService.saveBatch(forecastPowerUltraShortTermList);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        });


    }


    /**
     * 超短期算法调用
     *
     * @param forecastPowerShortTerms 未来小时短期预测数据
     * @param powerStationStatusDatas 当前时刻之前4小时内实际功率
     * @param now                     当前时间
     * @param capacity                开机容量
     * @return
     * @throws Exception
     */
    public List<ForecastPowerUltraShortTerm> getForecastPowerUltraShortTerm(List<ForecastPowerShortTerm> forecastPowerShortTerms, List<PowerStationStatusData> powerStationStatusDatas, Long now, BigDecimal capacity, String stationCode) throws Exception {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<ForecastData> forecastDataList = new ArrayList<>();
        for (ForecastPowerShortTerm forecastPowerShortTerm : forecastPowerShortTerms) {
            ForecastData forecastData = new ForecastData();
            forecastData.setC_FORECAST_TIME(simpleDateFormat.format(forecastPowerShortTerm.getForecastTime()));
            forecastData.setC_FP_VALUE(forecastPowerShortTerm.getFpValue());
            forecastDataList.add(forecastData);
        }


        List<RealPowerData> realPowerDataList = new ArrayList<>();
        for (PowerStationStatusData powerStationStatusData : powerStationStatusDatas) {
            RealPowerData realPowerData = new RealPowerData();

            realPowerData.setC_TIME(simpleDateFormat.format(powerStationStatusData.getTime()));
            realPowerData.setC_REAL_VALUE(powerStationStatusData.getRealValue());
            realPowerDataList.add(realPowerData);
        }
        PowerData powerData = new PowerData(simpleDateFormat.format(now), capacity, realPowerDataList, forecastDataList, forecastPowerShortTerms.size());

        HttpRequest request;
        HttpResponse response = null;
        try {
            // 构造请求对象
            request = HttpRequest.post("http://localhost:7999")
                    .form("data", JSONUtil.parse(powerData.getData()).toString())
                    .form("capacity", powerData.getCapacity())
                    .form("now", powerData.getNow())
                    .form("dataLength", powerData.getDataLength())
                    .form("stationCode", stationCode);
            // 发送请求并获取响应对象
            response = request.execute();
            ResponseApiBean responseApiBean = JsonBeanUtil.jsonToBeans("[" + response.body() + "]", ResponseApiBean.class).get(0);


            if (responseApiBean.getErrorCode().equals(1)) {
                log.info("算法超短期：{}，预测数据为：{}", responseApiBean.getMsg(), responseApiBean.getPredict());
                List<ForecastPowerUltraShortTerm> list = new ArrayList<>();
                for (int i = 0; i < responseApiBean.getPredict().size(); i++) {
                    ForecastPowerUltraShortTerm forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
                    forecastPowerUltraShortTerm.setFpValue(responseApiBean.getPredict().get(i).setScale(2, BigDecimal.ROUND_HALF_UP));
                    forecastPowerUltraShortTerm.setForecastTime(forecastPowerShortTerms.get(i).getForecastTime());
                    forecastPowerUltraShortTerm.setGenDate(new Date());
                    forecastPowerUltraShortTerm.setForecastManufactor("SYJY");
                    forecastPowerUltraShortTerm.setStationCode(stationCode);
//          forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E3);
                    list.add(forecastPowerUltraShortTerm);
                }

                return list;
            } else {
                log.info("算法超短期：{}，预测数据为：{}", responseApiBean.getMsg(), responseApiBean.getPredict());
                return new ArrayList<>();
            }
        } finally {
            response.close();
        }
    }

    @Data
    private class ForecastData {
        private String C_FORECAST_TIME;
        private BigDecimal C_FP_VALUE;
    }


    @Data
    private class PowerData {
        private String now;
        private BigDecimal capacity;
        private Integer dataLength;
        private AlgorithmData data;


        public PowerData(String now, BigDecimal capacity, List<RealPowerData> rp, List<ForecastData> dq, Integer dataLength) {
            this.now = now;
            this.data = new AlgorithmData();
            this.data.setRp(rp);
            this.data.setDq(dq);
            this.capacity = capacity;
            this.dataLength = dataLength;
        }

    }

    @Data
    private class AlgorithmData {
        private List<RealPowerData> rp;
        private List<ForecastData> dq;
    }

    @Data
    private class RealPowerData {
        private String C_TIME;
        private BigDecimal C_REAL_VALUE;
    }

    @Data
    private class ResponseApiBean {

        private Integer errorCode;
        private String msg;
        private List<BigDecimal> predict;

    }


    /**
     * 执行超短期预测
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
    public void executeForecast() {
        electricFieldService.list().forEach(e -> {
            String stationCode = e.getStationCode();
            // 根据场站类型执行相应超短期预测
            try {
                // 获取查询时间，从当前时间所处时间点标记时间开始查询，截至到96个时间点对应的标记时间
                String cdqUpMin = sysParameterService.getSysParameterAndStationCode("CDQ_UP_MIN", "0", stationCode);
                Long calTime = DateMomentUtil.getMomentTime(System.currentTimeMillis() + Integer.parseInt(cdqUpMin) * 1000 * 60, 1, 15 * 60 * 1000L);
                Long startTime = calTime + 15 * 1000 * 60L;
                String llcdq_point = sysParameterService.getSysParameterAndStationCode("FILE_LLCDQ_POINT", "16", stationCode);
                Integer forecastPoints = Integer.parseInt(llcdq_point);
                Integer forecastMinutes = forecastPoints * 15;
                // 结束时间增加15分钟为了防止文件先生成，实时表中最后一个时间点没有点位的问题
                Long endTime = DateUtils.addMinutes(new Date(startTime), forecastMinutes).getTime();

                // 查询该时间段内的短期预测功率
                List<ForecastPowerShortTerm> forecastPowerShortTermList = this.forecastPowerShortTermService.findByStationCodeAndStartTimeAndEndTimeAndForecastManufactor(stationCode, new Date(startTime), new Date(endTime),"SYJY");

//                Map<Date, List<ForecastPowerShortTerm>> forecastPowerShortTermsMap =
//                        forecastPowerShortTermList.stream().collect(Collectors.groupingBy(ForecastPowerShortTerm::getForecastTime));

//            List<ForecastPowerShortTerm> addForecastPowerShortTermList = new ArrayList<>();
//            // 判断短期数据是否缺点
//            for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + 15 * 60 * 1000L) {
//                if (forecastPowerShortTermsMap.get(tempTime) == null) {
//                    // 缺失时间点
//                    ForecastPowerShortTerm forecastPowerShortTerms = null;
//                    if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
//                        forecastPowerShortTerms = forecastPowerShortTermService.generateSolarPowerShortTerm(tempTime, openCapacityMap.get(tempTime), electricField);
//                    } else {
//                        forecastPowerShortTerms = forecastPowerShortTermService.generateWindPowerShortTerm(tempTime, openCapacityMap.get(tempTime));
//                    }
//                    addForecastPowerShortTermList.add(forecastPowerShortTerms);
//                }
//            }
//            if (!addForecastPowerShortTermList.isEmpty()) {
//                // 保存短期预测
//                this.forecastPowerShortTermRepository.saveAll(addForecastPowerShortTermList);
//                // 将补齐的预测功率追加到查询预测功率结果集中
//                forecastPowerShortTermList.addAll(addForecastPowerShortTermList);
//            }
                forecastPowerShortTermList.sort(Comparator.comparing(ForecastPowerShortTerm::getForecastTime));


                log.info("执行超短期预测生成。。。。。。{}",stationCode);
//                if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
//                    // 光伏电站
//                    this.executeForecastForlight(forecastPowerShortTermList, electricField.getCapacity());
//                } else if (ElectricFieldTypeEnum.E2.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
                // 风力电场
                this.executeForecastForWind(forecastPowerShortTermList, e.getCapacity(), e.getStationCode());
//                }
//                else {
//                    log.error("场站类型非法！");
//                }

            } catch (Exception ex) {
                log.error("系统运行错误！", ex);
            }
        });
    }


    /**
     * 执行风电场超短期预测
     *
     * @param forecastPowerShortTermList 短期预测结果集
     * @param capacity                   装机容量
     */
    private void executeForecastForWind(final List<ForecastPowerShortTerm> forecastPowerShortTermList, final BigDecimal capacity, String stationCode) {


        List<ForecastPowerUltraShortTerm> forecastPowerUltraShortTermList = new ArrayList<>();
        ForecastPowerUltraShortTerm forecastPowerUltraShortTerm;
        //获取系统参数cdqjsfs，超短期计算方式，0为默认乘系数的方式，1为根据可用功率计算的方式
        String cdqjsfs = sysParameterService.getSysParameterAndStationCode("cdqjsfs", "0", stationCode);
        log.info("参数cdqjsfs值为：" + cdqjsfs + "，超短期计算方式，0为默认乘系数的方式，1为根据可用功率计算的方式。");
        BigDecimal stPower, ustPower, ustPowers;
        // 查询当前时间点标记时间前10分钟的可用功率
        Date currentTime = new Date(System.currentTimeMillis());
        Date startTime = DateUtils.addMinutes(currentTime, -10);
        Date endTime = DateUtils.addMinutes(currentTime, 1);
        List<PowerStationStatusData> powerStationStatusDataList = powerStationStatusDataService.findByStationCodeAndStartTimeAndEndTime(stationCode, startTime, endTime);
        List<PowerStationStatusData> filterList = powerStationStatusDataList.stream().filter(t -> t.getAbleValue().compareTo(new BigDecimal("-1")) == 1).collect(Collectors.toList());
        String coe = sysParameterService.getSysParameterAndStationCode("CDQ_COE", "1.05", stationCode);

        Long monentTime = 0L;
        try {
            monentTime = DateMomentUtil.getMomentTime(new Date().getTime(), 1, 15 * 60 * 1000L);
        } catch (Exception e) {
            log.error("获取当前时刻错误", e);
        }

        if (filterList.size() > 0) {
            // 获取当前时刻对应的短期
            List<ForecastPowerShortTerm> currentForecastPowerShortTermList;
            BigDecimal currentForecastPowerValue = BigDecimal.ZERO;
            try {
                Long currentMoment = DateMomentUtil.getMomentTime(currentTime.getTime(), 1, 15 * 60 * 1000L);
                currentForecastPowerShortTermList = forecastPowerShortTermService.findByStationCodeAndStartTimeAndEndTime(stationCode, new Date(currentMoment), new Date(currentMoment));
                if (currentForecastPowerShortTermList.size() > 0) {
                    currentForecastPowerValue = currentForecastPowerShortTermList.get(0).getFpValue();
                } else {
                    // 当前时间没有对应的短期，用实际功率最近的一个替换
                    filterList.sort(Comparator.comparing(PowerStationStatusData::getTime).reversed());
                    currentForecastPowerValue = filterList.get(0).getAbleValue();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            BigDecimal sumAbleValue = filterList.stream().map(PowerStationStatusData::getAbleValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal averageAbleValue = sumAbleValue.divide(new BigDecimal(filterList.size()), 2, BigDecimal.ROUND_HALF_UP);
            //可用-短期差值
            BigDecimal deviationValue = averageAbleValue.subtract(currentForecastPowerValue);
            for (int i = 0; i < forecastPowerShortTermList.size(); i++) {
                forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
                forecastPowerUltraShortTerm.setForecastTime(forecastPowerShortTermList.get(i).getForecastTime());
                forecastPowerUltraShortTerm.setGenDate(new Date());
                forecastPowerUltraShortTerm.setForecastManufactor("SYJY");
                forecastPowerUltraShortTerm.setStationCode(stationCode);
                //短期
                stPower = forecastPowerShortTermList.get(i).getFpValue();
                //短期*系数
                ustPowers = stPower.multiply(new BigDecimal(coe)).setScale(2, BigDecimal.ROUND_HALF_UP);
                // 如果短期预测小于等于0，则超短期为0
                if (stPower.doubleValue() <= 0) {
                    forecastPowerUltraShortTerm.setFpValue(BigDecimal.ZERO);
                    forecastPowerUltraShortTerm.setDifferenceValue(BigDecimal.ZERO);
                    forecastPowerUltraShortTerm.setCoefficientValue(BigDecimal.ZERO);
                } else {
                    BigDecimal xzjdq = deviationValue.add(stPower).setScale(2, BigDecimal.ROUND_HALF_UP);
                    String cdqjsfsZbxz = sysParameterService.getSysParameterAndStationCode("cdqjsfsZbxz", "0.4", stationCode);
                    log.info("参数cdqjsfsZbxz值为：" + cdqjsfsZbxz + "，超短期计算方式，可用和短期的差值加短期占比。");
                    String cdqjsfsZbdq = sysParameterService.getSysParameterAndStationCode("cdqjsfsZbdq", "0.6", stationCode);
                    log.info("参数cdqjsfsZbdq值为：" + cdqjsfsZbdq + "，超短期计算方式，短期占比。");
                    ustPower = xzjdq.multiply(new BigDecimal(cdqjsfsZbxz)).setScale(2, BigDecimal.ROUND_HALF_UP).add(stPower.multiply(new BigDecimal(cdqjsfsZbdq)).setScale(2, BigDecimal.ROUND_HALF_UP));
                    if (ustPower.doubleValue() > capacity.doubleValue()) {
                        // 如果超短期结果超出装机容量，则超短期结果为装机容量
                        forecastPowerUltraShortTerm.setFpValue(capacity);
                    } else if (ustPower.doubleValue() < 0) {
                        // 如果超短期结果小于0，则超短期结果为0
                        forecastPowerUltraShortTerm.setFpValue(BigDecimal.ZERO);
                    } else {
                        if (cdqjsfs.equals("1")) {

                            forecastPowerUltraShortTerm.setFpValue(ustPower);
                        } else {
                            forecastPowerUltraShortTerm.setFpValue(ustPowers);
                        }
                    }
                    forecastPowerUltraShortTerm.setDifferenceValue(ustPower);
                    forecastPowerUltraShortTerm.setCoefficientValue(ustPowers);
                }
                forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
            }
        } else {
            log.info("库中没有可用，本次可用计算数据采用短期*系数的方式生成数据");

            // 短期乘以系数
            for (int i = 0; i < forecastPowerShortTermList.size(); i++) {
                stPower = forecastPowerShortTermList.get(i).getFpValue();
                ustPower = stPower.multiply(new BigDecimal(coe)).setScale(2, BigDecimal.ROUND_HALF_UP);
                forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
                forecastPowerUltraShortTerm.setForecastTime(forecastPowerShortTermList.get(i).getForecastTime());
                forecastPowerUltraShortTerm.setCoefficientValue(ustPower);
                forecastPowerUltraShortTerm.setDifferenceValue(new BigDecimal(-0.99).setScale(2, BigDecimal.ROUND_HALF_UP));
                forecastPowerUltraShortTerm.setFpValue(ustPower);
                forecastPowerUltraShortTerm.setGenDate(new Date());
                forecastPowerUltraShortTerm.setStationCode(stationCode);
                forecastPowerUltraShortTerm.setForecastManufactor("SYJY");
                forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
            }
        }

        int ago = 1;
        List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHisList = new ArrayList<>();

        for (ForecastPowerUltraShortTerm forecastPowerUltraShortTerm1 : forecastPowerUltraShortTermList) {
            // 构造ForecastPowerUltraShortTermHis对象
            ForecastPowerUltraShortTermHis forecastPowerUltraShortTermHis = new ForecastPowerUltraShortTermHis();
            forecastPowerUltraShortTermHis.setGenDate(new Date(monentTime));
            forecastPowerUltraShortTermHis.setStationCode(stationCode);
            forecastPowerUltraShortTermHis.setAbleValue(forecastPowerUltraShortTerm1.getFpValue());
            forecastPowerUltraShortTermHis.setForecastTime(forecastPowerUltraShortTerm1.getForecastTime());
            forecastPowerUltraShortTermHis.setForecastHowLongAgo(ago);
            forecastPowerUltraShortTermHis.setForecastManufactor("SYJY");
            forecastPowerUltraShortTermHisList.add(forecastPowerUltraShortTermHis);
            ago++;
        }

        // 删除之前的ForecastPowerUltraShortTerm记录
        LambdaQueryWrapper<ForecastPowerUltraShortTerm> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ForecastPowerUltraShortTerm::getStationCode, stationCode);
        lambdaQueryWrapper.eq(ForecastPowerUltraShortTerm::getForecastManufactor, "SYJY");
        lambdaQueryWrapper.between(ForecastPowerUltraShortTerm::getForecastTime, forecastPowerUltraShortTermList.get(0).getForecastTime(), forecastPowerUltraShortTermList.get(forecastPowerUltraShortTermList.size() - 1).getForecastTime());
        forecastPowerUltraShortTermService.remove(lambdaQueryWrapper);
        // 批量保存新的ForecastPowerUltraShortTerm记录
        forecastPowerUltraShortTermService.saveBatch(forecastPowerUltraShortTermList);

        // 删除当天的ForecastPowerUltraShortTermHis记录
        LambdaQueryWrapper<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHisLambdaQueryWrapper = new LambdaQueryWrapper<>();
        forecastPowerUltraShortTermHisLambdaQueryWrapper.eq(ForecastPowerUltraShortTermHis::getGenDate, new Date(monentTime));
        forecastPowerUltraShortTermHisLambdaQueryWrapper.eq(ForecastPowerUltraShortTermHis::getStationCode, stationCode);
        forecastPowerUltraShortTermHisLambdaQueryWrapper.eq(ForecastPowerUltraShortTermHis::getForecastManufactor, "SYJY");
        forecastPowerUltraShortTermHisService.remove(forecastPowerUltraShortTermHisLambdaQueryWrapper);
        // 批量保存新的ForecastPowerUltraShortTermHis记录
        forecastPowerUltraShortTermHisService.saveBatch(forecastPowerUltraShortTermHisList);


//        if (forecastPowerUltraShortTermList.size() > 0) {
//            // 获取数据开始时间和结束时间
//            Date oldStarTime = forecastPowerUltraShortTermList.get(0).getForecastTime();
//            Date oldEndTime = forecastPowerUltraShortTermList.get(forecastPowerShortTermList.size() - 1).getForecastTime();
//
//
//            // 保存超短期预测结果
//            this.forecastPowerUltraShortTermService.remove(Wrappers.lambdaQuery(ForecastPowerUltraShortTerm.class).between(ForecastPowerUltraShortTerm::getForecastTime, oldStarTime, oldEndTime).eq(ForecastPowerUltraShortTerm::getStationCode, stationCode));
//
//        }
//        List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHiss = new ArrayList<>();
//        int i = 1;
//        for (ForecastPowerUltraShortTerm f : forecastPowerUltraShortTermList) {
//            ForecastPowerUltraShortTermHis forecastPowerUltraShortTermHis = new ForecastPowerUltraShortTermHis();
//            forecastPowerUltraShortTermHis.setAbleValue(f.getFpValue());
//            forecastPowerUltraShortTermHis.setCapacity(capacity);
//            forecastPowerUltraShortTermHis.setForecastHowLongAgo(i);
//            forecastPowerUltraShortTermHis.setForecastTime(f.getForecastTime());
//            forecastPowerUltraShortTermHis.setForecastManufactor(f.getForecastManufactor());
//            forecastPowerUltraShortTermHis.setGenDate(f.getGenDate());
//            forecastPowerUltraShortTermHis.setSuCapacity(capacity);
//            forecastPowerUltraShortTermHis.setTheoryValue(f.getFpValue());
//            forecastPowerUltraShortTermHis.setStationCode(stationCode);
//            forecastPowerUltraShortTermHiss.add(forecastPowerUltraShortTermHis);
//            i++;
//        }
//
//        this.forecastPowerUltraShortTermHisService.saveBatch(forecastPowerUltraShortTermHiss);
//        this.forecastPowerUltraShortTermService.saveBatch(forecastPowerUltraShortTermList);

    }

    public LocalDateTime timestamToDatetime(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

}
