package com.jiayue.ipfcst.dataexchange.dataprocesser;

import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
import com.jiayue.ipfcst.common.data.entity.EnvironmentalData;
import com.jiayue.ipfcst.common.data.entity.EquipmentAttribute;
import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
import com.jiayue.ipfcst.common.data.repository.EnvironmentalDataRepository;
import com.jiayue.ipfcst.dataexchange.container.ProtocolDataContainer;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Random;

/**
 * 统计数据计算器
 *
 * @author: xiuwei
 * @version:
 */
@Data
@Slf4j
public class StatisticalDataCalculator {


  /**
   * 随机数
   */
  private static final Random RANDOM=new Random();

  /**
   * 随机数最小值
   */
  private static final BigDecimal COE_MIN=BigDecimal.valueOf(0.95);

  /**
   * 随机数活动区间
   */
  private static final BigDecimal COE_SCOPE=BigDecimal.valueOf(0.05);


  /**
   * 获取极大值转最大值的系数
   * @return
   */
  private static BigDecimal getCoefficient(){
    return BigDecimal.valueOf(RANDOM.nextDouble()).multiply(COE_SCOPE).add(COE_MIN).setScale(2, RoundingMode.HALF_UP);
  }

  /**
   * 设备类型
   */
  private final EquipmentTypeEnum equipmentType;
  /**
   * 设备编号
   */
  private final Integer equipmentNo;
  /**
   * 数据池的id
   */
  private final Integer pointId;
  /**
   * 该点对应的设备属性
   */
  private final EquipmentAttribute equipmentAttribute;
  /**
   * 数据所处于的日期
   */
  private DateTime date = DateTime.now().withMillisOfDay(0);
  /**
   * 存入数据库使用的id
   */
  private Integer id = null;
  /**
   * 可以视为一天之内的极大值
   */
  private BigDecimal maximum = null;
  /**
   * 可以视为一天之内的极小值
   */
  private BigDecimal minimum = null;
  /**
   * 平均值
   */
  private BigDecimal average = null;

  /**
   * 总值
   */
  private BigDecimal total = BigDecimal.ZERO;
  /**
   * 数据个数
   */
  private Integer dataNum = 0;
  /**
   * 最大数据的产生时间
   */
  private DateTime maximumDataTime = DateTime.now();
  /**
   * 最小数据产生的时间
   */
  private DateTime minimumDataTime = DateTime.now();


  public StatisticalDataCalculator(ProtocolGatherDataPoint dataPoint) {
    this.pointId = dataPoint.getId();
    this.equipmentAttribute = dataPoint.getEquipmentAttribute();
    this.equipmentNo = dataPoint.getEquipmentId();
    this.equipmentType = dataPoint.getEquipmentType();
    recoveryFromDataBase();
  }

  public synchronized void updateData() {
    //从池子内获取点位上的值
    BigDecimal realTimeValue = ProtocolDataContainer.getInstance().getNumber(pointId);
    if (realTimeValue.compareTo(BigDecimal.valueOf(-99)) == 0) {
      return;
    }
    if (maximum == null || realTimeValue.compareTo(maximum) > 0 || realTimeValue.compareTo(maximum) == 0) {
      //比最大值大 或者 相等
      //设置最大值
      maximum = realTimeValue;
      //设置最大值发生时间
      maximumDataTime = DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0);
    }
    if (minimum == null || realTimeValue.compareTo(minimum) < 0 || realTimeValue.compareTo(minimum) == 0) {
      //比最小值小 或者 相等
      //设置最小值
      minimum = realTimeValue;
      //设置最小值发生时间
      minimumDataTime = DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0);
    }
    total = total.add(realTimeValue);
    average = total.divide(BigDecimal.valueOf(++dataNum), 2, BigDecimal.ROUND_HALF_UP);
  }

  /**
   * 向数据库中保存数据
   */
  public void saveData() {
    EnvironmentalDataRepository environmentalDataRepository = SpringContextHolder.getBean(EnvironmentalDataRepository.class);
    EnvironmentalData environmentalData = extractEnvironmentalData();
    if (this.id == null) {
      List<EnvironmentalData> environmentalDates = environmentalDataRepository.queryByTimeAndAttr(environmentalData.getEquipmentTypeEnum(), environmentalData.getEquipmentId(), environmentalData.getEquipmentAttribute(), environmentalData.getStatisticalTime());
      if (environmentalDates != null && environmentalDates.size() > 0 && environmentalDates.get(0) != null) {
        //如果查询到记录后 设置记录id
        this.id = environmentalDates.get(0).getId();
        environmentalData.setId(environmentalDates.get(0).getId());
      }
    }
    environmentalDataRepository.save(environmentalData);
  }


  private EnvironmentalData extractEnvironmentalData() {
    EnvironmentalData environmentalData = new EnvironmentalData();
    environmentalData.setEquipmentAttribute(this.equipmentAttribute);
    environmentalData.setEquipmentTypeEnum(this.equipmentType);
    environmentalData.setEquipmentId(this.getEquipmentNo());
    environmentalData.setAvgValue(this.average);
    environmentalData.setMaxValue(this.maximum);
    if(environmentalData.getMaxValue()!=null) {
      environmentalData.setMaxAvgValue(environmentalData.getMaxValue().multiply(getCoefficient()).setScale(2, RoundingMode.HALF_UP));
    }
    environmentalData.setMinValue(this.minimum);
    if(environmentalData.getMinValue()!=null) {
      environmentalData.setMinAvgValue(environmentalData.getMinValue().divide(getCoefficient(),2,RoundingMode.HALF_UP));
    }
    environmentalData.setMaxValueTime(this.maximumDataTime.toDate());
    environmentalData.setMinValueTime(this.minimumDataTime.toDate());
    environmentalData.setStatisticalTime(this.date.toDate());
    environmentalData.setStatisticalDataNum(this.dataNum);
    environmentalData.setId(this.id);
    return environmentalData;
  }


  /**
   * 重置
   * 每天重置最大 最小 平均值
   * 以及数据的日期
   */
  public synchronized void reset() {
    log.info("跨越一天，重置统计值");
    this.maximum = null;
    this.minimum = null;
    this.total = BigDecimal.ZERO;
    this.dataNum = 0;
    this.date = DateTime.now().withMillisOfDay(0);
    this.id = null;
  }


  /**
   * 如果程序是中途停止运行后重启的 那么重启时 从数据库恢复文件
   */
  public void recoveryFromDataBase() {
    EnvironmentalDataRepository environmentalDataRepository = SpringContextHolder.getBean(EnvironmentalDataRepository.class);
    List<EnvironmentalData> environmentalDates = environmentalDataRepository.queryByTimeAndAttr(this.equipmentType, this.equipmentNo, this.equipmentAttribute, this.date.toDate());
    if (environmentalDates != null && environmentalDates.size() > 0 && environmentalDates.get(0) != null) {
      this.setId(environmentalDates.get(0).getId());
      this.setMaximum(environmentalDates.get(0).getMaxValue());
      this.setMinimum(environmentalDates.get(0).getMinValue());
      this.setAverage(environmentalDates.get(0).getAvgValue());
      this.setDataNum(environmentalDates.get(0).getStatisticalDataNum());
      this.setMaximumDataTime(new DateTime(environmentalDates.get(0).getMaxValueTime()));
      this.setMinimumDataTime(new DateTime(environmentalDates.get(0).getMinValueTime()));
      if (getAverage() != null && getDataNum() != null) {
        this.setTotal(getAverage().multiply(BigDecimal.valueOf(getDataNum())));
      }
      log.info("{}-{} 的{} 从数据库恢复数据，id:{},最大值:{},最小值:{},平均值:{},数据个数:{}", this.equipmentType.getMessage(), this.equipmentNo
        , this.equipmentAttribute.getExplanation(), this.id, this.maximum, this.minimum, this.average, this.dataNum);
    }
  }


}
