package com.jiayue.ipfcst.console.service;


import com.jiayue.ipfcst.common.core.util.CommonUtil;
import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
import com.jiayue.ipfcst.common.data.constant.enums.AlarmTypeEnum;
import com.jiayue.ipfcst.common.data.entity.Nwp;
import com.jiayue.ipfcst.common.data.entity.NwpHis;
import com.jiayue.ipfcst.common.data.repository.NwpHisRepository;
import com.jiayue.ipfcst.common.data.repository.NwpRepository;
import com.jiayue.ipfcst.common.data.service.BaseService;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@Slf4j
public class NwpService extends BaseService {

    @Autowired
    NwpRepository nwpRepository;
    @Autowired
    NwpHisRepository nwpHisRepository;


    /**
     * 保存全部
     *
     * @param listNwp
     */
    public void saveAll(List<Nwp> listNwp) {
        nwpRepository.saveAll(listNwp);
    }

    /**
     * 根据时间段删除数据
     *
     * @param startTime
     * @param endTime
     * @param listNwp
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteBetweenAndPreTime(Long startTime, Long endTime, List<Nwp> listNwp) {
        nwpRepository.deleteByPreTimeBetween(startTime, endTime);
        nwpRepository.saveAll(listNwp);
    }

    /**
     * 查询NWP数据，当查询结果不足时，需要本地化生成NWP数据并保存到数据库中，用于NWP数据上报时使用
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return NWP数据结果集
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Nwp> getNwpData(@NotNull final Long startTime, @NotNull final Long endTime) {
        log.info("开始获取NWP数据" + DateFormatUtils.format(startTime, "yyyy-MM-dd HH:mm:ss") + " 至 " + DateFormatUtils.format(endTime, "yyyy-MM-dd HH:mm:ss"));
        // 查询NWP数据
        List<Nwp> nwpDataList = this.nwpRepository.findByPreTimeBetween(startTime, endTime);
        nwpDataList.sort(Comparator.comparing(Nwp::getPreTime));// 按预测时间升序
        log.info("查询现有NWP数据记录数:" + nwpDataList.size());
        // 判断查询结果是否满足查询所需
        Long momentTime = 15 * 60 * 1000L; // 15分钟一个时刻
        Integer moments = Math.toIntExact((endTime - startTime) / momentTime + 1);
        log.info("获取所需记录数:" + moments);
        if (moments > nwpDataList.size()) {
            // 如果查询结果少于所需预测数，则进行本地化计算，补齐预测记录
            Map<Long, List<Nwp>> nwpDataMap = nwpDataList.stream().collect(Collectors.groupingBy(Nwp::getPreTime));
            // 如果查询结果少于所需预测数，则进行本地化计算，补齐预测记录
            List<Nwp> addNwpDataList = new ArrayList<>();
            for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {
                if (nwpDataMap.get(tempTime) == null) {
                    // 缺失时间点
                    List<Nwp> _nwpDataList = this.generateNwpData(tempTime);
                    addNwpDataList.addAll(_nwpDataList);
                }
            }

            if (!addNwpDataList.isEmpty()) {
                this.nwpRepository.saveAll(addNwpDataList);
                // 将补齐的NWP数据追加到查询结果集中
                nwpDataList.addAll(addNwpDataList);
                // 进行告警
                String errorInfo = "NWP数据不足";
                log.error(errorInfo);
                // 进行告警
                String name = "NWP数据不足";
                String describe = "";
                String solution = "请检查NWP数据下载软件";
                super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
            }

        }
        // 处理NWP历史数据记录
        List<NwpHis> nwpDataHiss = new ArrayList<>();
        NwpHis nwpHis;
        Long systemTime = new Date().getTime();

        for (Nwp nwp : nwpDataList) {
            nwpHis = new NwpHis();
            BeanUtils.copyProperties(nwp, nwpHis);
            // 设置提前几天预测
            nwpHis.setForecastHowLongAgo(DateMomentUtil.getDaysBetweenTwoDate(systemTime, nwpHis.getPreTime()));
            nwpDataHiss.add(nwpHis);
        }
        // 按预测时间升序
        nwpDataHiss.sort(Comparator.comparing(NwpHis::getPreTime));
        // 删除当日生成的短期历史记录
        this.nwpHisRepository.deleteToday(startTime, endTime);
        // 保存NWP历史记录
        this.nwpHisRepository.saveAll(nwpDataHiss);
        return nwpDataList;
    }

    /**
     * 生成NWP数据,NWP数据为云下载数据，这里不进行覆盖更新，只针对NWP数据不足时补充
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void buildNwpData(@NotNull final Long startTime, @NotNull final Long endTime) {
        this.getNwpData(startTime, endTime);
    }

    /**
     * 生成NWP数据
     *
     * @return nwp数据集
     */
    @Transactional(propagation = Propagation.REQUIRED)
    private List<Nwp> generateNwpData(@NotNull final Long tempTime) {

        List<Nwp> nwpDataList;

        // 使用历史NWP数据生成NWP数据
        List<Nwp> result = new ArrayList<>();
        // 查询前一天同时刻NWP数据
        nwpDataList = this.nwpRepository.findByPreTimeBetween(tempTime - 24 * 60 * 60 * 1000L, tempTime - 24 * 50 * 60 * 1000L);
        if (nwpDataList.size() > 0) {
            Nwp nwp = new Nwp();
            BeanUtils.copyProperties(nwpDataList.get(0), nwp, "id");
            nwp.setPreTime(tempTime);
            nwp.setPreDate(DateFormatUtils.format(tempTime, "yyyy-MM-dd"));
            result.add(nwp);
        } else {// 如果未查询到前一天数据，则随机生成NWP数据
            result.add(this.createNwpData(tempTime));
        }
        return result;
    }

    private Nwp createNwpData(Long preTime) {
        Long systemTime = System.currentTimeMillis();
        Nwp nwpData = new Nwp();
        nwpData.setFarmId("1");
        nwpData.setScDate(DateFormatUtils.format(systemTime, "yyyy-MM-dd"));
        nwpData.setScTime(DateFormatUtils.format(systemTime, "HH:mm:ss"));
        nwpData.setPreTime(preTime);
        nwpData.setPreDate(DateFormatUtils.format(preTime, "yyyy-MM-dd"));
        nwpData.setPressure(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setT(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setRh(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setSenf(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setSwr(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setLwr(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));

        nwpData.setWd10(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd30(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd50(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd70(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd80(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd90(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd100(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWd170(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs10(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs30(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs50(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs70(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs80(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs90(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs100(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        nwpData.setWs170(new BigDecimal(CommonUtil.getRandom(1, 5000) / 10.0).setScale(2,BigDecimal.ROUND_UP));
        return nwpData;
    }
}
