package com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.iml;

import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
import com.jiayue.ipfcst.common.data.entity.ForecastForSendAttribute;
import com.jiayue.ipfcst.common.data.entity.ForecastPowerShortTermHis;
import com.jiayue.ipfcst.common.data.entity.ForecastPowerUltraShortTermHis;
import com.jiayue.ipfcst.console.service.ForecastPowerShortTermService;
import com.jiayue.ipfcst.console.service.ForecastPowerUltraShortTermService;
import com.jiayue.ipfcst.console.service.SysParameterService;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.BaseDataGainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.NumOrBool;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.WindTowerStatusDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateUtils;
import org.joda.time.DateTime;

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

/**
 * 预测数据组装
 *
 * @author: xiuwei
 * @version:
 */
@Slf4j
public class ForecastDataGainer extends BaseDataGainer<BigDecimal> {


  /**
   * 预测数据
   */
  private static ForecastData forecastData = new ForecastData();


  /**
   * 预测数据的属性
   */
  ForecastForSendAttribute forecastForSendAttribute;

  /**
   * 构造方法
   *
   * @param forecastForSendAttribute 预测数据的属性
   * @param magnification            倍率
   */
  public ForecastDataGainer(ForecastForSendAttribute forecastForSendAttribute, Double magnification) {
    super(NumOrBool.NUM, magnification);
    this.forecastForSendAttribute = forecastForSendAttribute;
  }

  @Override
  public BigDecimal getData() throws DataExchangeException {
    BigDecimal val;
    switch (forecastForSendAttribute.getForecastType()) {
      case SHORT_AVAILABLE:
        val = forecastData.getShortAvailable(forecastForSendAttribute.getForecastNode() * 96 + forecastForSendAttribute.getPointNumber());
        break;
      case SHORT_THEORETICAL:
        val = forecastData.getShortTheoretical(forecastForSendAttribute.getForecastNode() * 96 + forecastForSendAttribute.getPointNumber());
        break;
      case ULTRA_SHORT_AVAILABLE:
        val = forecastData.getUltraShortAvailable(forecastForSendAttribute.getForecastNode() * 4 + forecastForSendAttribute.getPointNumber());
        break;
      case ULTRA_SHORT_THEORETICAL:
        val = forecastData.getUltraShortTheoretical(forecastForSendAttribute.getForecastNode() * 4 + forecastForSendAttribute.getPointNumber());
        break;
      default:
        val = BigDecimal.ZERO;
    }

    if (val != null) {
      val = val.multiply(BigDecimal.valueOf(getMagnification()));
    } else {
      val = BigDecimal.ZERO;
    }
    return val;
  }


  /**
   * 预测数据
   */
  static class ForecastData {

    /**
     * 短期的预测数据 service
     */
    private final ForecastPowerShortTermService forecastPowerShortTermService = SpringContextHolder.getBean(ForecastPowerShortTermService.class);

    /**
     * 超短期数据  service
     */
    private final ForecastPowerUltraShortTermService forecastPowerUltraShortTermService = SpringContextHolder.getBean(ForecastPowerUltraShortTermService.class);

    private final SysParameterService sysParameterService = SpringContextHolder.getBean(SysParameterService.class);


    /**
     * 刷新时更新上传数据
     */
    private static final String UPDATE_UPLOADED_DATA_WHEN_FLUSH = "updateUploadedDataWhenSenderFlush";

    /**
     * 刷新时更新上传数据
     */
    private static final String UPDATE_UPLOADED_DATA_WHEN_FLUSH_DEFAULT = "0";

    /**
     * 预测数据的查询 和更新 时间  开始的15分钟节点
     */
    DateTime updateTime;


    /**
     * 超短期可用数据  下一个15分钟节点 开始    如现在为13:25:30  那么开始时间为13:30:00  ， 未来的第 key 个点   第 key 个点的预测数据
     */
    Map<Integer, BigDecimal> ultraShortAvailable = new HashMap<>(16);


    /**
     * 短期可用数据  今天的 00:00:00 开始，     未来的第 key 个点   ，第 key 个点的预测数据
     */
    Map<Integer, BigDecimal> shortAvailable = new HashMap<>(1056);


    /**
     * 超短期理论数据  下一个15分钟节点 开始    如现在为13:25:30  那么开始时间为13:30:00 未来的第 key 个点   ，第 key 个点的预测数据
     */
    Map<Integer, BigDecimal> ultraShortTheoretical = new HashMap<>(16);


    /**
     * 短期理论数据  今天的 00:00:00 开始 开始    未来的第 key 个点   ，第 key 个点的预测数据
     */
    Map<Integer, BigDecimal> shortTheoretical = new HashMap<>(1056);


    /**
     * 获取超短期可用数据
     *
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public Map<Integer, BigDecimal> getUltraShortAvailable() {
      judgeUpdateTime();
      return this.ultraShortAvailable;
    }

    /**
     * 获取超短期理论数据
     *
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public Map<Integer, BigDecimal> getUltraShortTheoretical() {
      judgeUpdateTime();
      return this.ultraShortTheoretical;
    }

    /**
     * 获取短期可用数据
     *
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public Map<Integer, BigDecimal> getShortAvailable() {
      judgeUpdateTime();
      return this.shortAvailable;
    }

    /**
     * 获取短期理论数据
     *
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public Map<Integer, BigDecimal> getShortTheoretical() {
      judgeUpdateTime();
      return this.shortTheoretical;
    }


    /**
     * 获取单个超短期可用
     *
     * @param point
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public BigDecimal getUltraShortAvailable(Integer point) {
      return getUltraShortAvailable().get(point);
    }


    /**
     * 获取单个超短期理论
     *
     * @param point
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public BigDecimal getUltraShortTheoretical(Integer point) {
      return getUltraShortTheoretical().get(point);
    }

    /**
     * 获取单个短期可用
     *
     * @param point
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public BigDecimal getShortAvailable(Integer point) {
      return getShortAvailable().get(point);
    }


    /**
     * 获取单个短期理论
     *
     * @param point
     * @return Map<Integer, BigDecimal> 将来的15分钟段个数（第n个15分钟） 数值
     */
    public BigDecimal getShortTheoretical(Integer point) {
      return getShortTheoretical().get(point);
    }


    /**
     * 判断 预测数据更新时间  如果时间不在指定范围内 则更新数据
     */
    public void judgeUpdateTime() {
      // 如果当前时间为空
      // 如果当前时间 在  fromDate+15分钟 之后
      //重新加载数据
      if (this.updateTime == null || this.updateTime.plusMinutes(15).isBeforeNow()) {

        // 获取当前系统时间
        Date systemDate = new Date();
        // 开始时间
        Long l1 = null;
        try {
          l1 = DateMomentUtil.getMomentTime(systemDate.getTime() + 15 * 60 * 1000, 1, 15 * 60 * 1000L);
        } catch (Exception e) {
          e.printStackTrace();
        }
        // 结束时间
        Long l2 = l1 + 16 * 15 * 60 * 1000;
        List<ForecastPowerUltraShortTermHis> ultraForecastData;
        try {
          ultraForecastData = forecastPowerUltraShortTermService.getForecastPowerUltraShortTerm(l1, l2);
        } catch (Exception e) {
          log.error("转发通道获取超短期数据时发生异常", e);
          this.updateTime = DateTime.now();
          return;
        }
        ultraForecastData.sort(Comparator.comparingLong(ForecastPowerUltraShortTermHis::getForecastTime));
        for (int i = 0; i < ultraForecastData.size(); i++) {
          ultraShortAvailable.put(i + 1, ultraForecastData.get(i).getAbleValue());
          ultraShortTheoretical.put(i + 1, ultraForecastData.get(i).getTheoryValue());
        }
        //今天的 00:00:00
        l1 = DateMomentUtil.getDayStartTime(systemDate.getTime());
        // 结束时间（开始加24小时再减去1秒） 10第10天
        l2 = DateMomentUtil.getDayLastTime(DateUtils.addDays(systemDate, 10).getTime());

        List<ForecastPowerShortTermHis> forecastData;
        try {
          if (UPDATE_UPLOADED_DATA_WHEN_FLUSH_DEFAULT.equals(sysParameterService.getSysParameter(UPDATE_UPLOADED_DATA_WHEN_FLUSH, UPDATE_UPLOADED_DATA_WHEN_FLUSH_DEFAULT))) {
            //默认刷新时不刷新已上报数据
            forecastData = forecastPowerShortTermService.getForecastPowerShortTermHis(l1, l2);
          } else {
            forecastData = forecastPowerShortTermService.getForecastPowerShortTerm(l1, l2);
          }
        } catch (Exception e) {
          log.error("转发通道获取短期数据时发生异常", e);
          this.updateTime = DateTime.now();
          return;
        }
        forecastData.sort(Comparator.comparingLong(ForecastPowerShortTermHis::getForecastTime));
        for (int i = 0; i < forecastData.size(); i++) {
          shortAvailable.put(i + 1, forecastData.get(i).getAbleValue());
          shortTheoretical.put(i + 1, forecastData.get(i).getTheoryValue());
        }
        this.updateTime = DateTime.now();
      }
    }
  }
}
