package com.jiayue.insu.incloud.pushdata;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jiayue.insu.incloud.compermisson.QNHLComPermisson;
import com.jiayue.insu.incloud.constants.CommonStant;
import com.jiayue.insu.incloud.constants.CompanyConstant;
import com.jiayue.insu.incloud.constants.enums.QNHLEnum;
import com.jiayue.insu.incloud.constants.enums.StatusEnum;
import com.jiayue.insu.incloud.constants.vo.RequestVo;
import com.jiayue.insu.incloud.constants.vo.ResponseVo;
import com.jiayue.insu.incloud.entity.*;
import com.jiayue.insu.incloud.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 清能推送数据
 *
 * @author yh
 * @version 1.0
 * @since 2022/5/22 11:29
 */
@Component
@Slf4j
public class PushDataForQNHL implements IPushInitForecastData {

    @Autowired
    private ForecastDataService forecastDataService;
    @Autowired
    private StationService stationService;
    @Autowired
    private IntegrationCompanyService integrationCompanyService;
    @Autowired
    private QNHLComPermisson qNHLComPermisson;
    @Autowired
    private RecordService recordService;
    @Autowired
    private PowerGenerationService powerGenerationService;
    @Autowired
    private MonthPowerGenerationService monthPowerGenerationService;

    /**
     * 推送原始预测数据
     *
     * @param station 场站信息
     * @return 是否成功
     */
    @Override
    public Boolean pushDQAndNWPData(Station station) {

        Record record = new Record();
        record.setStationCode(station.getStationCode());
        record.setInCode(station.getInCode());
        record.setType(CommonStant.RECORD_TYPE_PUSH_INIT);
        LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        record.setTime(localDateTime);
        record.setCreateTime(LocalDateTime.now());

        Station st = stationService.findByStationCode(station.getStationCode());
        String token = st.getComKey();
        LocalDateTime tokenTime = st.getKeyTime();

        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(CompanyConstant.COMPANY_QNHL);
        String dataPushUrl = integrationCompany.getPushUrl();


        boolean result = false;
        String response;
        RequestVo requestVo;

        if (StrUtil.isEmpty(token)  || LocalDateTime.now().isAfter(tokenTime)) {
            if(qNHLComPermisson.generateKey(station)){
                st = stationService.findByStationCode(station.getStationCode());
                token  = st.getComKey();
                tokenTime  = st.getKeyTime();
            }
        }

        if (StrUtil.isNotEmpty(token) &&  LocalDateTime.now().isBefore(tokenTime)) {
        long startTime = DateUtil.beginOfDay(new Date()).getTime();
        long endTime = DateUtil.offsetDay(DateUtil.beginOfDay(DateUtil.tomorrow()), st.getDays()).getTime();
        long momentTime = 900000L;
        List<ForecastData> aList;
        aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
        aList.sort(Comparator.comparing(ForecastData::getForecastTime));

        if (CollectionUtil.isNotEmpty(aList)) {

            /**************************补点 start*************************/
            if (aList.get(0).getForecastTime().longValue() != startTime) {
                List<ForecastData> bList = new ArrayList<>();
                long finallyTime = aList.get(0).getForecastTime().longValue();
                ForecastData source = aList.get(0);
                for (Long tempTime = startTime; tempTime < finallyTime; tempTime = tempTime + momentTime) {
                    ForecastData target = new ForecastData();
                    BeanUtil.copyProperties(source, target, false);
                    target.setId(null);
                    target.setForecastTime(tempTime);
                    bList.add(target);

                }
                forecastDataService.saveBatch(bList);
                aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
                aList.sort(Comparator.comparing(ForecastData::getForecastTime));
            }
            /**************************补点 end*************************/

            BigDecimal one = new BigDecimal("1");
            BigDecimal checkCount = new BigDecimal(st.getDays().toString()).add(one).multiply(new BigDecimal("96")).add(one);
            //如果数据小于961条 不上送数据
            if (aList.size() >= checkCount.intValue()) {

                if (CommonStant.ET_PHOTOVOLTAIC.equals(station.getType())) {
                    requestVo = generatePhotovoltaicRequest(station.getSignCode(), aList, startTime, endTime, station.getStationCode());
                } else {
                    requestVo = generateWindRequest(station.getSignCode(), aList, startTime, endTime);
                }

                JSONObject json = JSONUtil.parseObj(requestVo, false);
                String body = json.toString();

                try {

                    HttpRequest httpRequest = HttpRequest.post(dataPushUrl)
                            .header("Content-Type", "application/json")
                            .header("Authorization", token);
                    httpRequest.setGlobalTimeout(20000);

                    response = httpRequest
                            .body(body)
                            .execute().body();

                    if (StrUtil.isNotEmpty(response)) {
                        boolean isJson = JSONUtil.isJsonObj(response);
                        if (isJson) {
                            ResponseVo responseVo = JSONUtil.toBean(response, ResponseVo.class);
                            String code = responseVo.getRetCode();
                            if (code.equals(QNHLEnum.REQUEST_SUCCESS.getCode())) {

                                for (ForecastData a : aList) {
                                    a.setUploadTime(LocalDateTime.now());
                                }
                                forecastDataService.saveOrUpdateBatch(aList);
                                record.setState(QNHLEnum.REQUEST_SUCCESS.getSign());
                                record.setStateContent(String.valueOf(aList.size()));
                                result = true;
                                log.info("=========={}:{} ==>上送短期原始数据成功  {}条==========", integrationCompany.getName(), st.getStationCode(), aList.size());
                            } else {
                                QNHLEnum[] values = QNHLEnum.values();
                                for (QNHLEnum q : values) {
                                    if (code.equals(q.getCode())) {
                                        log.error("=========={}:{} ==>上送数据失败 失败标识:{} ,失败原因：{} ==========", integrationCompany.getName(), st.getStationCode(), code, responseVo.getRetMsg());
                                        record.setState(q.getSign());
                                        record.setStateContent(q.getMsg());
                                        if (q.name().startsWith("PERMISSON")) {
                                            log.error("=========={}:{} ==>重新请求token ==========", integrationCompany.getName(), st.getStationCode(), code);
                                            qNHLComPermisson.generateKey(station);
                                        }
                                    }

                                }

                            }
                        } else {
                            record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                            record.setStateContent(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getMsg());
                            log.error("=========={}:{} ==>上送短期原始数据失败 接收响应字符串非json格式 ", integrationCompany.getName(), st.getStationCode());
                        }
                    } else {
                        record.setState(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getSign());
                        record.setStateContent(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getMsg());
                        log.error("=========={}:{} ==>上送短期原始数据失败  返回响应内容为空 ==========", integrationCompany.getName(), st.getStationCode());
                    }
                } catch (Exception e) {

                    record.setState(StatusEnum.CONNECT_ERROR.getSign());
                    record.setStateContent(StatusEnum.CONNECT_ERROR.getMsg());
                    log.error("=========={}:{} ==>上送短期原始数据失败 连接断开或请求超时 ==========", integrationCompany.getName(), st.getStationCode());
                    e.printStackTrace();

                }


            } else {

                record.setState(StatusEnum.DATA_DEFICIENCY.getSign());
                record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                log.warn("=========={}:{} ==>上送短期原始数据失败 上送数据不足 不上送数据 ==========", integrationCompany.getName(), st.getStationCode());
            }


        } else {
            record.setState(StatusEnum.DATA_DEFICIENCY.getSign());
            record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
            log.warn("=========={}:{} ==>上送短期原始数据失败 上送数据查询为空 不上送数据 ==========", integrationCompany.getName(), st.getStationCode());
        }

        } else {

            record.setState(QNHLEnum.PERMISSON_LOGIN_NOT.getSign());
            record.setStateContent(QNHLEnum.PERMISSON_LOGIN_NOT.getMsg());
            log.error("=========={}:{} ==>上送短期原始数据失败 无token ==========",integrationCompany.getName(),st.getStationCode());
        }

        recordService.save(record);

        return result;
    }

    /**
     * 生成光短期请求
     *
     * @return RequestVo
     */
    public RequestVo generatePhotovoltaicRequest(String el, List<ForecastData> aList, long startTime, long endTime, String stationCode) {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        String queryDateStr = simpleDateFormat.format(new Date());

        Date queryDate = null;

        try {
            queryDate = simpleDateFormat.parse(queryDateStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        DateTime dateTime = DateUtil.parse(DateUtil.now());

        String fileName = el + "_" + dateTime.toString("yyyyMMdd_HHmm") + "_" + QNHLEnum.DATA_FORE_TYPE.getSign() + ".CIME";

        String content = "";

        Long momentTime = 900000L; // 15分钟一个时刻

        String header = "<! Entity=" + el + "  time='" + dateTime.toString("yyyy-MM-dd HH:mm:ss") + "' !>" + CommonStant.LINE_CONSTANT;
        String labelStart = "<ForecastPower>" + CommonStant.LINE_CONSTANT;
        String labelEnd = "</ForecastPower>" + CommonStant.LINE_CONSTANT;
        String title = "@" + CommonStant.SPACE1_CONSTANT + "序号" + CommonStant.SPACE4_CONSTANT + "时间"
                + CommonStant.SPACE4_CONSTANT + "功率预测" + CommonStant.SPACE4_CONSTANT + "总辐照度"
                + CommonStant.SPACE4_CONSTANT + "直射辐照度" + CommonStant.SPACE4_CONSTANT + "散射辐照度"
                + CommonStant.SPACE4_CONSTANT + "温度" + CommonStant.SPACE4_CONSTANT + "湿度" + CommonStant.SPACE4_CONSTANT
                + "气压" + CommonStant.SPACE4_CONSTANT + "风速" + CommonStant.SPACE4_CONSTANT + " 风向" + CommonStant.LINE_CONSTANT;
        content += header;
        content += labelStart;
        content += title;
        String template = "#" + CommonStant.SPACE1_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.LINE_CONSTANT;


        Map<Long, List<ForecastData>> forecastMap =
                aList.stream().collect(Collectors.groupingBy(ForecastData::getForecastTime));

        int i = 1;

        for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {

            List<ForecastData> list = forecastMap.get(tempTime);

            String time = DateUtil.date(tempTime).toString("yyyyMMddHHmmss");

            if (CollectionUtil.isNotEmpty(list)) {
                ForecastData aioForecastPowerShortTerm = forecastMap.get(tempTime).get(0);
                String dataStr = StrUtil.format(template,
                        i,
                        time,
                        aioForecastPowerShortTerm.getFpValue() == null ? "NULL" : aioForecastPowerShortTerm.getFpValue().setScale(6).toString(),
                        aioForecastPowerShortTerm.getSwr() == null ? "NULL" : aioForecastPowerShortTerm.getSwr().setScale(6).toString(),
                        aioForecastPowerShortTerm.getDirectRadiation() == null ? "NULL" : aioForecastPowerShortTerm.getDirectRadiation().setScale(6).toString(),
                        aioForecastPowerShortTerm.getDiffuseRadiation() == null ? "NULL" : aioForecastPowerShortTerm.getDiffuseRadiation().setScale(6).toString(),
                        aioForecastPowerShortTerm.getTemperature() == null ? "NULL" : aioForecastPowerShortTerm.getTemperature().setScale(6).toString(),
                        aioForecastPowerShortTerm.getHumidity() == null ? "NULL" : aioForecastPowerShortTerm.getHumidity().setScale(6).toString(),
                        aioForecastPowerShortTerm.getPressure() == null ? "NULL" : aioForecastPowerShortTerm.getPressure().setScale(6).toString(),
                        aioForecastPowerShortTerm.getWindSpeed() == null ? "NULL" : aioForecastPowerShortTerm.getWindSpeed().setScale(6).toString(),
                        aioForecastPowerShortTerm.getWindDir() == null ? "NULL" : aioForecastPowerShortTerm.getWindDir().setScale(6).toString()
                );
                content += dataStr;

            } else {
                String dataStr = StrUtil.format(template,
                        i,
                        time,
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL"
                );
                content += dataStr;
            }


            i++;
        }

        content += labelEnd;

        // 浙江一体化新增年月日发电量/海南
        if (el.equals("ZJSYJYGY") || el.equals("HNSYJYYLW")) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
            String nowYear = sdf.format(new Date());

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

            String nextYear = String.valueOf(Integer.valueOf(nowYear) + 1);
            List<MonthPowerGeneration> monthPowerGenerationList = monthPowerGenerationService.findByGenDateAndStationCode(queryDate, stationCode);
            List<PowerGeneration> powerGenerationList = powerGenerationService.findByStationCodeAndInitTime(stationCode, queryDate);
            // 年预测发电量
            String yearLabelStart = "<YearForecastEnergy>" + CommonStant.LINE_CONSTANT;
            String yearLabelEnd = "</YearForecastEnergy>" + CommonStant.LINE_CONSTANT;
            String powerGenerationTitle = "@" + CommonStant.SPACE1_CONSTANT + "序号" + CommonStant.SPACE4_CONSTANT + "日期" + CommonStant.SPACE4_CONSTANT + "预测电量" + CommonStant.LINE_CONSTANT;
            content = content + CommonStant.LINE_CONSTANT + yearLabelStart + powerGenerationTitle;

            // 判断是否符合年预测电量上送日期
            if (judgeDate.contains("10-15") || judgeDate.contains("11-15")) {
                String yearTemplate = "#"
                        + CommonStant.SPACE1_CONSTANT + "{}"
                        + CommonStant.SPACE4_CONSTANT + "{}"
                        + CommonStant.SPACE4_CONSTANT + "{}"
                        + CommonStant.LINE_CONSTANT;
                if (monthPowerGenerationList.size() > 0) {
                    double yearValue = monthPowerGenerationList.stream()
                            .mapToDouble(MonthPowerGeneration::getPredictedElectricityConsumption)
                            .filter(value -> value >= 0).sum();
                    String dataStr = StrUtil.format(yearTemplate,
                            1,
                            nextYear,
                            yearValue
                    );
                    content += dataStr;
                } else {
                    String dataStr = StrUtil.format(yearTemplate,
                            1,
                            "NULL",
                            "NULL"
                    );
                    content += dataStr;
                }

            }

            content += yearLabelEnd;
            // 月预测发电量
            String monthLabelStart = "<MonthForecastEnergy>" + CommonStant.LINE_CONSTANT;
            String monthLabelEnd = "</MonthForecastEnergy>" + CommonStant.LINE_CONSTANT;
            content = content + CommonStant.LINE_CONSTANT + monthLabelStart + powerGenerationTitle;
            String monthTemplate = "#"
                    + CommonStant.SPACE1_CONSTANT + "{}"
                    + CommonStant.SPACE4_CONSTANT + "{}"
                    + CommonStant.SPACE4_CONSTANT + "{}"
                    + CommonStant.LINE_CONSTANT;

            if (monthPowerGenerationList.size() > 0) {
                // 升序排列
                monthPowerGenerationList = monthPowerGenerationList.stream().sorted(Comparator.comparing(MonthPowerGeneration::getForecastTime)).collect(Collectors.toList());
                for (int j = 1; j < 3; j++) {
                    String dataStr = StrUtil.format(monthTemplate,
                            j,
                            monthPowerGenerationList.get(j - 1).getForecastTime(),
                            monthPowerGenerationList.get(j - 1).getPredictedElectricityConsumption() == 0.0 ? "NULL" : monthPowerGenerationList.get(j - 1).getPredictedElectricityConsumption()
                    );
                    content += dataStr;
                }

            } else {
                for (int j = 1; j < 3; j++) {
                    String dataStr = StrUtil.format(monthTemplate,
                            j,
                            "NULL",
                            "NULL"
                    );
                    content += dataStr;
                }
            }
            content += monthLabelEnd;

            // 日预测发电量
            String dayLabelStart = "<DayForecastEnergy>" + CommonStant.LINE_CONSTANT;
            String dayLabelEnd = "</DayForecastEnergy>" + CommonStant.LINE_CONSTANT;
            content = content + CommonStant.LINE_CONSTANT + dayLabelStart + powerGenerationTitle;
            String dayTemplate = "#"
                    + CommonStant.SPACE1_CONSTANT + "{}"
                    + CommonStant.SPACE4_CONSTANT + "{}"
                    + CommonStant.SPACE4_CONSTANT + "{}"
                    + CommonStant.LINE_CONSTANT;
            if (powerGenerationList.size() > 0) {
                // 升序
                powerGenerationList.stream().sorted(Comparator.comparing(PowerGeneration::getForecastTime)).collect(Collectors.toList());
                // 过滤掉本月预测发电量
                powerGenerationList = powerGenerationList.stream().filter(f -> !f.getForecastTime().equals(new SimpleDateFormat("yyyyMMdd").format(new Date()))).collect(Collectors.toList());

                for (int j = 0; j < powerGenerationList.size(); j++) {
                    String dataStr = StrUtil.format(dayTemplate,
                            j + 1,
                            powerGenerationList.get(j).getForecastTime(),
                            powerGenerationList.get(j).getPredictedElectricityConsumption() == 0.0 ? "NULL" : powerGenerationList.get(j).getPredictedElectricityConsumption()
                    );
                    content += dataStr;
                }

            } else {
                for (int j = 0; j < 31; j++) {
                    String dataStr = StrUtil.format(dayTemplate,
                            j + 1,
                            "NULL",
                            "NULL"
                    );
                    content += dataStr;
                }

            }
            content += dayLabelEnd;
        }
        RequestVo requestVo = RequestVo.builder()
                .transferType(QNHLEnum.TRANSFER_TYPE_DOWNLOAD.getCode())
                .date(dateTime.toString("yyyyMMdd"))
                .dataType(QNHLEnum.DATA_FORE_TYPE.getSign())
                .fileName(fileName)
                .data(content).build();

        return requestVo;
    }


    /**
     * 生成风短期请求
     *
     * @return RequestVo
     */
    public RequestVo generateWindRequest(String el, List<ForecastData> aList, long startTime, long endTime) {

        DateTime dateTime = DateUtil.parse(DateUtil.now());

        String fileName = el + "_" + dateTime.toString("yyyyMMdd_HHmm") + "_" + QNHLEnum.DATA_FORE_TYPE.getSign() + ".CIME";

        StringBuilder content = new StringBuilder();

        long momentTime = 900000L; // 15分钟一个时刻

        String header = "<! Entity=" + el + "  time='" + dateTime.toString("yyyy-MM-dd HH:mm:ss") + "' !>" + CommonStant.LINE_CONSTANT;
        String labelStart = "<ForecastPower>" + CommonStant.LINE_CONSTANT;
        String labelEnd = "</ForecastPower>" + CommonStant.LINE_CONSTANT;
        String title = "@" + CommonStant.SPACE1_CONSTANT + "序号" + CommonStant.SPACE4_CONSTANT + "时间"
                + CommonStant.SPACE4_CONSTANT + "功率预测" + CommonStant.SPACE4_CONSTANT + "风速"
                + CommonStant.SPACE4_CONSTANT + "风向" + CommonStant.SPACE4_CONSTANT + "温度"
                + CommonStant.SPACE4_CONSTANT + "湿度" + CommonStant.SPACE4_CONSTANT + "气压" + CommonStant.LINE_CONSTANT;
        content.append(header);
        content.append(labelStart);
        content.append(title);
        String template = "#" + CommonStant.SPACE1_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.SPACE4_CONSTANT + "{}"
                + CommonStant.LINE_CONSTANT;


        Map<Long, List<ForecastData>> forecastMap =
                aList.stream().collect(Collectors.groupingBy(ForecastData::getForecastTime));

        int i = 1;

        for (long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {


            List<ForecastData> list = forecastMap.get(tempTime);

            String time = DateUtil.date(tempTime).toString("yyyyMMddHHmmss");

            if (CollectionUtil.isNotEmpty(list)) {

                ForecastData aioForecastPowerShortTerm = list.get(0);

                String dataStr = StrUtil.format(template, i, time,
                        aioForecastPowerShortTerm.getFpValue() == null ? "NULL" : aioForecastPowerShortTerm.getFpValue().setScale(6).toString(),
                        aioForecastPowerShortTerm.getWindSpeed() == null ? "NULL" : aioForecastPowerShortTerm.getWindSpeed().setScale(6).toString(),
                        aioForecastPowerShortTerm.getWindDir() == null ? "NULL" : aioForecastPowerShortTerm.getWindDir().setScale(6).toString(),
                        aioForecastPowerShortTerm.getTemperature() == null ? "NULL" : aioForecastPowerShortTerm.getTemperature().setScale(6).toString(),
                        aioForecastPowerShortTerm.getHumidity() == null ? "NULL" : aioForecastPowerShortTerm.getHumidity().setScale(6).toString(),
                        aioForecastPowerShortTerm.getPressure() == null ? "NULL" : aioForecastPowerShortTerm.getPressure().setScale(6).toString()
                );

                content.append(dataStr);

            } else {
                String dataStr = StrUtil.format(template, i, time,
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL",
                        "NULL"
                );

                content.append(dataStr);
            }

            i++;
        }

        content.append(labelEnd);

        RequestVo requestVo = RequestVo.builder()
                .transferType(QNHLEnum.TRANSFER_TYPE_DOWNLOAD.getCode())
                .date(dateTime.toString("yyyyMMdd"))
                .dataType(QNHLEnum.DATA_FORE_TYPE.getSign())
                .fileName(fileName)
                .data(content.toString()).build();

        return requestVo;
    }


    @Override
    public Boolean pushDQData(Station station) {

        return null;
    }

    @Override
    public Boolean pushNWPData(Station station) {
        return false;
    }


}
