package com.jiayue.ipfcst.service;

import com.jiayue.ipfcst.common.core.exception.BusinessException;
import com.jiayue.ipfcst.common.data.entity.ElectricField;
import com.jiayue.ipfcst.common.data.entity.ForecastPowerUltraShortTerm;
import com.jiayue.ipfcst.common.data.entity.PowerStationStatusData;
import com.jiayue.ipfcst.common.data.repository.ForecastPowerUltraShortTermRepository;
import com.jiayue.ipfcst.common.data.repository.PowerStationStatusDataRepository;
import com.jiayue.ipfcst.common.data.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 超短期预测实时业务层
 *
 * @author yh
 * @version 1.0
 * @since 2019/8/5 16:02
 */
@Service
public class ForecastPowerUltraShortTermService extends BaseService {

    private final ForecastPowerUltraShortTermRepository forecastPowerUltraShortTermRepository;
    private final PowerStationStatusDataRepository powerStationStatusDataRepository;

    private final ElectricFieldService electricFieldService;
    @Autowired
    public ForecastPowerUltraShortTermService(ForecastPowerUltraShortTermRepository forecastPowerUltraShortTermRepository,PowerStationStatusDataRepository powerStationStatusDataRepository,ElectricFieldService electricFieldService){
        this.forecastPowerUltraShortTermRepository = forecastPowerUltraShortTermRepository;
        this.powerStationStatusDataRepository = powerStationStatusDataRepository;
        this.electricFieldService = electricFieldService;
    }
  /**
   * 按时间查询实时预测超短期 yh
   * @param startTime 开始时间
   * @param endTime 结束时间
   * @return 结果集
   */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Map<String,Object> findByForecastTimeBetween(Long startTime, Long endTime) throws BusinessException {

      Map<String,Object> map = new HashMap<>();
      List<ForecastPowerUltraShortTerm> list = new ArrayList<>();
      list = forecastPowerUltraShortTermRepository.findByForecastTimeBetween(startTime, endTime);
      list.sort(Comparator.comparing(ForecastPowerUltraShortTerm::getForecastTime));

      List<PowerStationStatusData> powerStationStatusDataList = powerStationStatusDataRepository.findByTimeBetween(new Date(startTime), new Date(endTime));

      List<Float> realValueDatas = new ArrayList<>();
      List<Float> ableValueDatas = new ArrayList<>();
      List<Float> theoryValueDatas = new ArrayList<>();

      long startTimeLong  = startTime;
      long endTimeLong  = endTime;
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      long timeStep = 900000L;
      if(startTimeLong%timeStep !=0){
        startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
      }
      List<Float> datas = new ArrayList<>();
      List<String> times = new ArrayList<>();

      for(long i = startTimeLong;i<endTimeLong;i=i+timeStep){
        long finalI = i;
        List<ForecastPowerUltraShortTerm> p = list.stream().filter(t -> t.getForecastTime() == finalI).collect(Collectors.toList());
        PowerStationStatusData powerStationStatusData = powerStationStatusDataList.stream().filter(o -> sdf.format(o.getTime()).equals(sdf.format(new Date(finalI)))).findAny().orElse(null);

        if (p != null && p.size() > 0) {
          datas.add(p.get(0).getFpValue().floatValue());
        }else{
          datas.add(null);
        }
        if(powerStationStatusData!=null){
          realValueDatas.add(powerStationStatusData.getRealValue().floatValue());
          ableValueDatas.add(powerStationStatusData.getAbleValue().floatValue());
          theoryValueDatas.add(powerStationStatusData.getTheoryValue().floatValue());
        }
        String timeFormat = sdf.format(new Date(i));
        times.add(timeFormat);
      }
      ElectricField electricField = electricFieldService.get();
      map.put("times",times);
      map.put("datas",datas);
      map.put("realValueDatas", realValueDatas);
      map.put("ableValueDatas", ableValueDatas);
      map.put("theoryValueDatas", theoryValueDatas);
      map.put("capacity", electricField.getCapacity());
      return map;
    }


  /**
   * 查询实时超短期（用于考核综合对比页面） yh
   * @param startTime 开始时间
   * @param endTime 结束时间
   * @return 结果集
   */
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
  public Map<String,Object> findByForecastTimeBetweenForComprehensive(Long startTime, Long endTime,Long timeStep) throws BusinessException {

    Map<String,Object> map = new HashMap<>();
    List<ForecastPowerUltraShortTerm> list = new ArrayList<>();
    list = forecastPowerUltraShortTermRepository.findByForecastTimeBetween(startTime, endTime);
    list.sort(Comparator.comparing(ForecastPowerUltraShortTerm::getForecastTime));

    long startTimeLong  = startTime;
    long endTimeLong  = endTime;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    if(startTimeLong%timeStep !=0){
      startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
    }
    List<Float> datas = new ArrayList<>();
    List<String> times = new ArrayList<>();

    for(long i = startTimeLong;i<endTimeLong;i=i+timeStep){
      long finalI = i;
      List<ForecastPowerUltraShortTerm> p = list.stream().filter(t -> t.getForecastTime() == finalI).collect(Collectors.toList());
      if (p != null && p.size() > 0) {
        datas.add(p.get(0).getFpValue().floatValue());
      }else{
        datas.add(null);
      }
      String timeFormat = sdf.format(new Date(i));
      times.add(timeFormat);
    }
    map.put("times",times);
    map.put("datas",datas);
    return map;
  }



  /**
   * 根据时间 分页查询 实时预测超短期数据 yh
   *
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @param page      页码
   * @param size      条数
   * @param sortOrder 排序
   * @return
   */
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
  public Map<String, Object> findByTimeBetweenAndNoForPaging(Long startTime, Long endTime,
                                                             Integer page, Integer size,
                                                             String sortOrder)  {
    Map<String, Object> map = new HashMap<>();
    Sort sort = Sort.by(Sort.Direction.DESC, "forecastTime");
    if (sortOrder.contains("asc")) {
      sort = Sort.by(Sort.Direction.ASC, "forecastTime");
    }
    Specification<ForecastPowerUltraShortTerm> specification = this.specificationFindByTimeAndNo(startTime, endTime);
    Pageable pageable = PageRequest.of(page - 1, size, sort);
    Page forecastPowerUltraShortTerms = forecastPowerUltraShortTermRepository.findAll(specification,pageable);
    List<ForecastPowerUltraShortTerm> datas = new ArrayList<>();
    datas = forecastPowerUltraShortTerms.getContent();
    map.put("content", datas);
    map.put("count", forecastPowerUltraShortTerms.getTotalElements());
    return map;
  }

  /**
   * 根据时间和编号 分页查询条件 yh
   *
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @return 过滤条件
   */
  Specification<ForecastPowerUltraShortTerm> specificationFindByTimeAndNo(final Long startTime, final Long endTime) {
    return (Specification<ForecastPowerUltraShortTerm>) (root, criteriaQuery, cb) -> {
      List<Predicate> predicates = new ArrayList<>();
      if (startTime!=null) {
        //大于或等于传入时间
        predicates.add(cb.greaterThanOrEqualTo(root.get("forecastTime").as(Long.class), startTime));
      }
      if (endTime!=null) {
        //小于传入时间
        predicates.add(cb.lessThan(root.get("forecastTime").as(Long.class), endTime));
      }

      //添加排序的功能
      return cb.and(predicates.toArray(new Predicate[predicates.size()]));

    };
  }
}
