package com.jiayue.ipfcst.dataexchange.service;

import com.jiayue.ipfcst.common.data.entity.Nwp;
import com.jiayue.ipfcst.common.data.entity.WeatherStationStatusData;
import com.jiayue.ipfcst.common.data.entity.WindTowerStatusData;
import com.jiayue.ipfcst.common.data.repository.NwpRepository;
import com.jiayue.ipfcst.console.service.SysParameterService;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.WeatherStationStatusDataService;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.WindTowerStatusDataService;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 环境数据生成器
 * 用于生成环境数据 包括测风塔和气象站
 * 要求再生成假数据后  假数据能与前一点相互关联呼应，保持曲线平滑过渡。
 *
 * @author xiuwei
 * @date 2021/09/15
 */
@Service
@Slf4j
public class EnvironmentDataAnyTimeGenerator extends EnvironmentDataGenerator {


  /**
   * 风塔数据生成器
   */
  public Map<Integer, WindTowerDataGenerator> windTowerDataGenerators = new HashMap<>();


  /**
   * 气象站数据生成器
   */
  public Map<Integer, WeatherStationDataGenerator> weatherStationDataGenerators = new HashMap<>();

  public EnvironmentDataAnyTimeGenerator(WindTowerStatusDataService windTowerStatusDataService, WeatherStationStatusDataService weatherStationStatusDataService, NwpRepository nwpRepository, SysParameterService sysParameterService) {
    super(windTowerStatusDataService, weatherStationStatusDataService, nwpRepository, sysParameterService);
  }


  /**
   * 风塔数据生成器
   *
   * @param windTowerId 风塔id
   * @return {@link WindTowerDataGenerator}
   */
  public WindTowerDataGenerator getWindTowerDataGenerator(Integer windTowerId) {
    if (!this.windTowerDataGenerators.containsKey(windTowerId)) {
      this.windTowerDataGenerators.put(windTowerId, new WindTowerDataGenerator(windTowerId));
    }
    return this.windTowerDataGenerators.get(windTowerId);
  }

  /**
   * 气象站数据生成器
   *
   * @param weatherStationId 气象站id
   * @return {@link WeatherStationDataGenerator}
   */
  public WeatherStationDataGenerator getWeatherStationDataGenerator(Integer weatherStationId) {
    if (!this.weatherStationDataGenerators.containsKey(weatherStationId)) {
      this.weatherStationDataGenerators.put(weatherStationId, new WeatherStationDataGenerator(weatherStationId));
    }
    return this.weatherStationDataGenerators.get(weatherStationId);
  }


  /**
   * 测风塔数据生成器
   *
   * @author xiuwei
   * @date 2021/09/15
   */
  public class WindTowerDataGenerator extends EnvironmentDataGenerator.WindTowerDataGenerator {


    /**
     * 下一时间段的NWP
     */
    Nwp nextTimeNwp;


    DateTime time;

    public WindTowerDataGenerator(Integer windTowerId) {
      super(windTowerId);
    }

    /**
     * 获取下一时刻的预测环境数据
     *
     * @return {@link Nwp}
     */
    private Nwp getNextTimeNwp(DateTime time) {
      Long startTime = time.getMillis();
      if (nextTimeNwp != null) {
        if (this.nextTimeNwp.getPreTime() - startTime > 0)
          return this.nextTimeNwp;
      }
      Long endTime = startTime + 15 * 60 * 1000;
      List<Nwp> nwps = nwpRepository.findByPreTimeBetween(startTime, endTime);
      if (nwps.size() > 0) {
        nextTimeNwp = nwps.get(0);
      }
      return nextTimeNwp;
    }


    /**
     * 得到上一次风塔数据
     * 会自动更新数据
     *
     * @return {@link WindTowerStatusData}
     */
    private WindTowerStatusData getPreWindTowerData(DateTime time) {
      //如果pWindTowerData 为空 或者时间 距离现在超过一分钟  就需要从数据库取出
      if (this.pWindTowerData != null) {
        if (this.pWindTowerData.getTime().after(time.minusMinutes(15).toDate())) {
          return this.pWindTowerData;
        }
      }
      List<WindTowerStatusData> l = windTowerStatusDataService.findByEquipmentNoAndTimeBetween(this.windTowerId, time.minusMinutes(15).toDate(), time.toDate());
      if (l.size() == 0) {
        //没有
        this.pWindTowerData = null;
      } else {
        this.pWindTowerData = l.get(l.size() - 1);
      }
      return this.pWindTowerData;
    }


    /**
     * 获取趋势点 未来某点最近的预测点的风速值 并根据一个点的预测风速生成各层的预测风速 共20层
     *
     * @return {@link WindTowerStatusData}
     */
    private WindTowerStatusData getForecastWindData(DateTime time) {
      this.time = time;
      if (this.fWindTowerData == null || this.fWindTowerData.getTime().before(this.time.plusMinutes(15).toDate())) {
        this.fWindTowerData = new WindTowerStatusData();
        Nwp nwp = getNextTimeNwp(time);
        this.fWindTowerData = nwpToWindTowerStatusData(nwp);
      }
      return this.fWindTowerData;
    }


    /**
     * 通过趋势点的时间以及风速 推算出现在的数据
     *
     * @return {@link WindTowerStatusData}
     */
    public WindTowerStatusData generateWindTowerData(DateTime time) {
      //生成所用的测风塔数据用于 后期填补数据
      WindTowerStatusData gWindTowerData = new WindTowerStatusData();
      gWindTowerData.setEquipmentNo(this.windTowerId);
      try {
      //预测的下一刻的测风塔数据
      WindTowerStatusData fWindTowerData = getForecastWindData(time);
      //上一时刻所使用的测风塔数据
      WindTowerStatusData pWindTowerData = getPreWindTowerData(time);
      //System.out.println("F=>"+fWindTowerData.iToString());
        if (pWindTowerData == null) {
          this.pWindTowerData = fWindTowerData;
          pWindTowerData = getPreWindTowerData(time);
        } else {
          if (this.pWindTowerData.getTime().after(time.minusMinutes(1).toDate())) {
            this.pWindTowerData.setTime(time.toDate());
            return pWindTowerData;
          }
        }
        //1.判断时间差值  分钟差
        int min = (int) (fWindTowerData.getTime().getTime() - time.getMillis()) / (60 * 1000);
        if (min == 0) {
          min = 15;
        }
        generateWindTowerDataByPreAndForecast(gWindTowerData, pWindTowerData, fWindTowerData, min);
        gWindTowerData.setTime(time.toDate());
        this.pWindTowerData = gWindTowerData;
      } catch (Exception e) {
        log.warn("测风塔{}生成假数据时发生异常,返回前一时刻数据。", windTowerId, e);
        this.pWindTowerData.setTime(time.toDate());
        return this.pWindTowerData;
      }
      return gWindTowerData;
    }
  }


  /**
   * 气象站数据生成器
   *
   * @author xiuwei
   * @date 2021/10/19
   */
  public class WeatherStationDataGenerator extends EnvironmentDataGenerator.WeatherStationDataGenerator {


    public WeatherStationDataGenerator(Integer weatherStationId) {
      super(weatherStationId);
    }

    /**
     * 得到上一次气象站数据
     * 会自动更新数据
     *
     * @return {@link WindTowerStatusData}
     */
    public WeatherStationStatusData getPreWeatherStationStatusData() {
      //如果pWindTowerData 为空 或者时间 距离现在超过一分钟  就需要从数据库取出
      if (this.pWeatherStationStatusData != null) {
        if (this.pWeatherStationStatusData.getTime().after(DateTime.now().minusMinutes(1).toDate())) {
          return this.pWeatherStationStatusData;
        }
      }
      List<WeatherStationStatusData> l = weatherStationStatusDataService.findByEquipmentNoAndTimeBetween(this.weatherStationId, DateTime.now().minusMinutes(1).toDate(), DateTime.now().toDate());
      if (l.size() == 0) {
        //没有
        this.pWeatherStationStatusData = null;
      } else {
        this.pWeatherStationStatusData = l.get(0);
      }
      return this.pWeatherStationStatusData;
    }

    /**
     * 获取趋势点 未来某点最近的预测点的风速值 并根据一个点的预测风速生成各层的预测风速 共20层
     *
     * @return {@link WindTowerStatusData}
     */
    public WeatherStationStatusData getForecastWeatherStationStatusData() {
      if (this.fWeatherStationStatusData == null || this.fWeatherStationStatusData.getTime().before(DateTime.now().plusMillis(15).toDate())) {
        this.fWeatherStationStatusData = new WeatherStationStatusData();
        //TODO
        Nwp nwp = null;
        this.fWeatherStationStatusData.setTime(new Date(nwp.getPreTime()));
        //风速
        this.fWeatherStationStatusData.setWs(nwp.getWs10());
        //风向
        this.fWeatherStationStatusData.setWd(nwp.getWd10());
        //总辐射
        this.fWeatherStationStatusData.setGlobalR(nwp.getSwr());
        //散射辐射
        this.fWeatherStationStatusData.setDiffuseR(nwp.getDiffuseRadiation());
        //直辐射
        this.fWeatherStationStatusData.setDirectR(nwp.getDirectRadiation());
        //温度
        this.fWeatherStationStatusData.setAirT(nwp.getT());
        //湿度
        this.fWeatherStationStatusData.setRh(nwp.getRh());
        //气压
        this.fWeatherStationStatusData.setP(nwp.getPressure());
      }
      return this.fWeatherStationStatusData;
    }


    public WeatherStationStatusData generateWeatherStationData() {
      //预测的下一刻的气象站数据
      WeatherStationStatusData fWeatherStationStatusData = getForecastWeatherStationStatusData();
      //生成所用的气象站数据用于 后期填补数据
      WeatherStationStatusData gWeatherStationStatusData = new WeatherStationStatusData();
      //上一时刻所使用的气象站数据
      WeatherStationStatusData pWeatherStationStatusData = getPreWeatherStationStatusData();
      //TODO  上一时刻数据
      if (pWeatherStationStatusData == null) {
        this.pWeatherStationStatusData = fWeatherStationStatusData;
        pWeatherStationStatusData = getPreWeatherStationStatusData();
      } else {
        if (this.pWeatherStationStatusData.getTime().after(DateTime.now().minusMinutes(1).toDate())) {
          return pWeatherStationStatusData;
        }
      }
      //1.判断时间差值  分钟差
      int min = (int) (fWeatherStationStatusData.getTime().getTime() - DateTime.now().getMillis()) / (60 * 1000);
      if (min == 0) {
        min = 15;
      }
      gWeatherStationStatusData.setGlobalR(getNextValOfWs(pWeatherStationStatusData.getGlobalR(), fWeatherStationStatusData.getGlobalR(), min));
      gWeatherStationStatusData.setDirectR(getNextValOfWs(pWeatherStationStatusData.getDirectR(), fWeatherStationStatusData.getDirectR(), min));
      gWeatherStationStatusData.setDiffuseR(getNextValOfWs(pWeatherStationStatusData.getDiffuseR(), fWeatherStationStatusData.getDiffuseR(), min));
      gWeatherStationStatusData.setAirT(getNextValOfWs(pWeatherStationStatusData.getAirT(), fWeatherStationStatusData.getAirT(), min));
      gWeatherStationStatusData.setP(getNextValOfWs(pWeatherStationStatusData.getP(), fWeatherStationStatusData.getP(), min));
      gWeatherStationStatusData.setRh(getNextValOfWs(pWeatherStationStatusData.getRh(), fWeatherStationStatusData.getRh(), min));
      gWeatherStationStatusData.setWs(getNextValOfWs(pWeatherStationStatusData.getWs(), fWeatherStationStatusData.getWs(), min));
      gWeatherStationStatusData.setWd(getNextValOfWd(fWeatherStationStatusData.getWd()));
      //日照时长累积
      if (pWeatherStationStatusData.getHourDA() == null || pWeatherStationStatusData.getHourDA().compareTo(BigDecimal.valueOf(-99)) == 0) {
        pWeatherStationStatusData.setHourDA(BigDecimal.ZERO);
      }
      gWeatherStationStatusData.setHourDA(gWeatherStationStatusData.getGlobalR().compareTo(BigDecimal.ZERO) > 0 ? pWeatherStationStatusData.getHourDA().add(BigDecimal.valueOf(0.017)) : pWeatherStationStatusData.getHourDA());
      //总累
      if (pWeatherStationStatusData.getGlobalRDA() == null || pWeatherStationStatusData.getGlobalRDA().compareTo(BigDecimal.valueOf(-99)) == 0) {
        pWeatherStationStatusData.setGlobalRDA(BigDecimal.ZERO);
      }
      gWeatherStationStatusData.setGlobalRDA(pWeatherStationStatusData.getGlobalR().add(BigDecimal.valueOf(0.017).multiply(gWeatherStationStatusData.getGlobalR())));

      //散累
      if (pWeatherStationStatusData.getDiffuseRDA() == null || pWeatherStationStatusData.getDiffuseRDA().compareTo(BigDecimal.valueOf(-99)) == 0) {
        pWeatherStationStatusData.setDiffuseRDA(BigDecimal.ZERO);
      }
      gWeatherStationStatusData.setDiffuseRDA(pWeatherStationStatusData.getDiffuseRDA().add(BigDecimal.valueOf(0.017).multiply(gWeatherStationStatusData.getDiffuseR())));

      //直累
      if (pWeatherStationStatusData.getDirectRDA() == null || pWeatherStationStatusData.getDirectRDA().compareTo(BigDecimal.valueOf(-99)) == 0) {
        pWeatherStationStatusData.setDirectRDA(BigDecimal.ZERO);
      }
      gWeatherStationStatusData.setDirectRDA(pWeatherStationStatusData.getDirectRDA().add(BigDecimal.valueOf(0.017).multiply(gWeatherStationStatusData.getDirectR())));

      gWeatherStationStatusData.setTime(DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0).toDate());
      gWeatherStationStatusData.setIsGenerated(true);

      return gWeatherStationStatusData;
    }

  }


}
