package com.jiayue.ipfcst.service;

import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.common.data.repository.WeatherStationStatusDataRepository;
import com.jiayue.ipfcst.common.data.service.BaseService;
import com.jiayue.ipfcst.repository.ProtocolGatherDataPointRepository;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
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.math.BigDecimal;
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 WeatherStationStatusDataService extends BaseService {

    private final WeatherStationStatusDataRepository weatherStationStatusDataRepository;

    @Autowired
    public WeatherStationStatusDataService(WeatherStationStatusDataRepository weatherStationStatusDataRepository){
       this.weatherStationStatusDataRepository = weatherStationStatusDataRepository;
    }

    /**
     * 根据开始时间和结束时间，设备编号 查询 环境监测仪数据 yh
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param no   设备编号
     * @return 结果集
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Map<String,Object> findByTimeBetweenAndEquipmentNo(Date startTime, Date endTime, Integer no){
      Map<String,Object> map = new HashMap<>();
      List<WeatherStationStatusData> list = new ArrayList<>();
      List<WeatherStationStatusData> checkList = new ArrayList<>();
      list = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(startTime,endTime,no);
      list.sort(Comparator.comparing(WeatherStationStatusData::getTime));
      long startTimeLong  = startTime.getTime();
      long endTimeLong  = endTime.getTime();
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      List<String> times = new ArrayList<>();
      long timeStep = 300000L;
      if(startTimeLong%timeStep !=0){
        startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
      }

      for(long i = startTimeLong;i<endTimeLong;i=i+300000L) {
        long finalI =i;
        List<WeatherStationStatusData> w = list.stream().filter(t -> t.getTime().getTime() == finalI).collect(Collectors.toList());
        if (w != null && w.size() > 0) {
          checkList.add(w.get(0));
        }else{
          checkList.add(new WeatherStationStatusData());
        }
        String timeFormat = sdf.format(new Date(i));
        times.add(timeFormat);
      }

      List<Float> globalRDatas = new ArrayList<>();
      List<Float> directRDatas = new ArrayList<>();
      List<Float> diffuseRDatas = new ArrayList<>();
      List<Float> obliqueRDatas = new ArrayList<>();
      Map<String,Object> radiationMap = new HashMap<>();

      List<Float> airTDatas = new ArrayList<>();
      List<Float> cellTDatas = new ArrayList<>();
      Map<String,Object> aAndCMap = new HashMap<>();

      List<Float> pDatas = new ArrayList<>();
      List<Float> rhDatas = new ArrayList<>();
      List<Float> wsDatas = new ArrayList<>();
      List<Float> wdDatas = new ArrayList<>();
      Map<String,Object> otherMap = new HashMap<>();

      BigDecimal nullValue = new BigDecimal(-99);

      List<BigDecimal> globalRs = checkList.stream().map(WeatherStationStatusData::getGlobalR).collect(Collectors.toList());
      for(BigDecimal b :globalRs){
          if (b.compareTo(nullValue)==0){
            globalRDatas.add(null);
          }else{
            globalRDatas.add(b.floatValue());
          }
      }

      List<BigDecimal> directRs = checkList.stream().map(WeatherStationStatusData::getDirectR).collect(Collectors.toList());
      for(BigDecimal b :directRs){
        if (b.compareTo(nullValue)==0){
          directRDatas.add(null);
        }else{
          directRDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> diffuseRs = checkList.stream().map(WeatherStationStatusData::getDiffuseR).collect(Collectors.toList());
      for(BigDecimal b :diffuseRs){
        if (b.compareTo(nullValue)==0){
          diffuseRDatas.add(null);
        }else{
          diffuseRDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> obliqueRs = checkList.stream().map(WeatherStationStatusData::getObliqueR).collect(Collectors.toList());
      for(BigDecimal b :obliqueRs){
        if (b.compareTo(nullValue)==0){
          obliqueRDatas.add(null);
        }else{
          obliqueRDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> airTs = checkList.stream().map(WeatherStationStatusData::getAirT).collect(Collectors.toList());
      for(BigDecimal b :airTs){
        if (b.compareTo(nullValue)==0){
          airTDatas.add(null);
        }else{
          airTDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> cellTs = checkList.stream().map(WeatherStationStatusData::getCellT).collect(Collectors.toList());
      for(BigDecimal b :cellTs){
        if (b.compareTo(nullValue)==0){
          cellTDatas.add(null);
        }else{
          cellTDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> ps = checkList.stream().map(WeatherStationStatusData::getP).collect(Collectors.toList());
      for(BigDecimal b :ps){
        if (b.compareTo(nullValue)==0){
          pDatas.add(null);
        }else{
          pDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> rhs = checkList.stream().map(WeatherStationStatusData::getRh).collect(Collectors.toList());
      for(BigDecimal b :rhs){
        if (b.compareTo(nullValue)==0){
          rhDatas.add(null);
        }else{
          rhDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> wss = checkList.stream().map(WeatherStationStatusData::getWs).collect(Collectors.toList());
      for(BigDecimal b :wss){
        if (b.compareTo(nullValue)==0){
          wsDatas.add(null);
        }else{
          wsDatas.add(b.floatValue());
        }
      }

      List<BigDecimal> wds = checkList.stream().map(WeatherStationStatusData::getWd).collect(Collectors.toList());
      for(BigDecimal b :wds){
        if (b.compareTo(nullValue)==0){
          wdDatas.add(null);
        }else{
          wdDatas.add(b.floatValue());
        }
      }

      radiationMap.put("globalRs",globalRDatas);
      radiationMap.put("directRs",directRDatas);
      radiationMap.put("diffuseRs",diffuseRDatas);
      radiationMap.put("obliqueRs",obliqueRDatas);

      aAndCMap.put("airTs",airTDatas);
      aAndCMap.put("cellTs",cellTDatas);

      otherMap.put("ps",pDatas);
      otherMap.put("rhs",rhDatas);
      otherMap.put("wss",wsDatas);
      otherMap.put("wds",wdDatas);

      map.put("times",times);
      map.put("radiationMap",radiationMap);
      map.put("aAndCMap",aAndCMap);
      map.put("otherMap",otherMap);
      return map;
    }

  /**
   * 根据开始时间和结束时间，设备编号 查询 环境监测仪数据 yh
   *
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @param no   设备编号
   * @return 结果集
   */
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
  public Map<String,Object> findByTimeBetweenAndEquipmentNoForContrast(Date startTime, Date endTime, Integer no){
    Map<String,Object> map = new HashMap<>();
    List<WeatherStationStatusData> list = new ArrayList<>();
    List<Float> datas = new ArrayList<>();
      list = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(startTime,endTime,no);
    Collections.sort(list, Comparator.comparing(WeatherStationStatusData::getTime));
    long startTimeLong  = startTime.getTime();
    long endTimeLong  = endTime.getTime();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    List<String> times = new ArrayList<>();
    long timeStep = 900000L;
    if(startTimeLong%timeStep !=0){
      startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
    }
    BigDecimal nullValue = new BigDecimal(-99);
    for(long i = startTimeLong;i<endTimeLong;i=i+timeStep) {
      long finalI =i;
      List<WeatherStationStatusData> w = list.stream().filter(t -> t.getTime().getTime() == finalI).collect(Collectors.toList());
      if (w != null && w.size() > 0) {
        WeatherStationStatusData wResult = w.get(0);
        if(wResult.getGlobalR().compareTo(nullValue) != 0 ){
          datas.add(wResult.getGlobalR().floatValue());
        }else{
          datas.add(null);
        }
      }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 no   设备编号
   * @return 结果集
   */
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
  public List<WeatherStationStatusData> findByTimeBetweenAndEquipmentNoForContrastData(Date startTime, Date endTime, Integer no,Long timeStep){
//    Map<String,Object> map = new HashMap<>();
    List<WeatherStationStatusData> list = new ArrayList<>();
    List<Float> datas = new ArrayList<>();
    List<WeatherStationStatusData> resultList = new ArrayList<>();
    list = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(startTime,endTime,no);

    long startTimeLong  = startTime.getTime();
    long endTimeLong  = endTime.getTime();
    if(startTimeLong%timeStep !=0){
      startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
    }
    for(long i = startTimeLong;i<endTimeLong;i=i+timeStep) {
      long finalI =i;
      List<WeatherStationStatusData> w = list.stream().filter(t -> t.getTime().getTime() == finalI).collect(Collectors.toList());
      if(w.size()>0){
        resultList.add(w.get(0));
      }
    }

    return resultList;
  }

    /**
     * 分页查询 环境监测仪数据 yh
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param no        设备编号
     * @param page      页码
     * @param size      条数
     * @param sortOrder 排序
     * @return
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Map<String, Object> findByTimeBetweenForPaging(Date startTime, Date endTime,
                                                          Integer page, Integer size,
                                                          Integer no, String sortOrder) {
        Map<String, Object> map = new HashMap<>();
        Sort sort = Sort.by(Sort.Direction.DESC, "time");
        if (sortOrder.contains("asc")) {
            sort = Sort.by(Sort.Direction.ASC, "time");
        }
        Specification<WeatherStationStatusData> specification = this.Specification(startTime, endTime,no);
        Pageable pageable = PageRequest.of(page - 1, size, sort);
        Page weatherStationStatusDatas = weatherStationStatusDataRepository.findAll(specification,pageable);
        List<WeatherStationStatusData> datas = weatherStationStatusDatas.getContent();
        this.defaultReplace(datas);
        map.put("content", datas);
        map.put("count", weatherStationStatusDatas.getTotalElements());
        return map;
    }

  /**
   * 分页查询 环境监测仪数据 tl
   *
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @param no        设备编号
   * @param sortOrder 排序
   * @return
   */
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
  public Map<String, Object> findByTimeBetweenAndNoAndTimeStep(Date startTime, Date endTime,
                                               Integer no,Long timeStep,String sortOrder) {
    Map<String, Object> map = new HashMap<>();

    List<WeatherStationStatusData> list = new ArrayList<>();
    List<Float> datas = new ArrayList<>();
    List<WeatherStationStatusData> resultList = new ArrayList<>();
    list = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(startTime,endTime,no);

    long startTimeLong  = startTime.getTime();
    long endTimeLong  = endTime.getTime();
    if(startTimeLong%timeStep !=0){
      startTimeLong = startTimeLong -(startTimeLong%timeStep)+timeStep;
    }
    for(long i = startTimeLong;i<endTimeLong;i=i+timeStep) {
      long finalI =i;
      List<WeatherStationStatusData> w = list.stream().filter(t -> t.getTime().getTime() == finalI).collect(Collectors.toList());
      if(w.size()>0){
        resultList.add(w.get(0));
      }
    }
    List<WeatherStationStatusData> collect = null;
    if (sortOrder.contains("asc")) {
      collect= resultList.stream().sorted(Comparator.comparing(WeatherStationStatusData::getTime)).collect(Collectors.toList());
    }else {
      collect= resultList.stream().sorted(Comparator.comparing(WeatherStationStatusData::getTime).reversed()).collect(Collectors.toList());
    }

    this.defaultReplace(collect);
    map.put("content", collect);
    map.put("count", resultList.size());


    return map;
  }


    /**
     * 查询条件 yh
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param no       设备编号
     * @return 过滤条件
     */
    Specification<WeatherStationStatusData> Specification(final Date startTime, final Date endTime,final Integer no) {
        return (Specification<WeatherStationStatusData>) (root, criteriaQuery, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (startTime!=null) {
                //大于或等于传入时间
                predicates.add(cb.greaterThanOrEqualTo(root.get("time").as(Date.class), startTime));
            }
            if (endTime!=null) {
                //小于传入时间
                predicates.add(cb.lessThan(root.get("time").as(Date.class), endTime));
            }
            if(no!=null){
                predicates.add(cb.equal(root.get("equipmentNo").as(Integer.class), no));
            }
            //添加排序的功能
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));

        };
    }

  /**
   *  对集合进行 -99替换null操作
   *
   * @param datas  需要替换集合
   */
  public void defaultReplace(List<WeatherStationStatusData> datas){
    BigDecimal nullBig =  new BigDecimal(-99);
    for(WeatherStationStatusData w:datas){

      if(w.getDirectR().compareTo(nullBig)==0){
        w.setDirectR(null);
      }

      if(w.getGlobalR().compareTo(nullBig)==0){
        w.setGlobalR(null);
      }

      if(w.getDiffuseR().compareTo(nullBig)==0){
        w.setDiffuseR(null);
      }

      if(w.getObliqueR().compareTo(nullBig)==0){
        w.setObliqueR(null);
      }

      if(w.getAirT().compareTo(nullBig)==0){
        w.setAirT(null);
      }

      if(w.getP().compareTo(nullBig)==0){
        w.setP(null);
      }

      if(w.getRh().compareTo(nullBig)==0){
        w.setRh(null);
      }

      if(w.getCellT().compareTo(nullBig)==0){
        w.setCellT(null);
      }

      if(w.getWs().compareTo(nullBig)==0){
        w.setWs(null);
      }

      if(w.getWd().compareTo(nullBig)==0){
        w.setWd(null);
      }

      if(w.getHourDA().compareTo(nullBig)==0){
        w.setHourDA(null);
      }

      if(w.getGlobalRDA().compareTo(nullBig)==0){
        w.setGlobalRDA(null);
      }

      if(w.getDirectRDA().compareTo(nullBig)==0){
        w.setDirectRDA(null);
      }

      if(w.getDiffuseRDA().compareTo(nullBig)==0){
        w.setDiffuseRDA(null);
      }

      if(w.getObliqueRDA().compareTo(nullBig)==0){
        w.setObliqueRDA(null);
      }

    }

  }

  /**
   * 统计查询：气象站数据查询
   *
   */
  public List<Map<String, Object>> findWeatherData(Long startTime, Long endTime, Integer no, String dateType,String dataType){

    List<Map<String,Object>> dataList = new ArrayList<>();
    List<WeatherStationStatusData> list = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(new Date(startTime),new Date(endTime),no);
    Map<String,Object> map = new HashMap<>();

    Map<String, List<Float>> afterFormatting = null;
    String date = "yyyyMMdd";
    //进行年月日判断
    if(dateType.equals("year")){
      date = "yyyy";
    }else if(dateType.equals("month")) {
      date = "yyyyMM";
    }


    List<Map<String,Float>> beforeFormatting = new ArrayList<>();

      Map<String,Object> tempMap = new HashMap<>();
      for (WeatherStationStatusData n:list) {
        Map<String,Float> map1 = new HashMap();
        if(dataType.equals("总辐射")){
          map1.put(DateFormatUtils.format(n.getTime(),date),n.getGlobalR().floatValue());
        }else if(dataType.equals("直接辐射")){
          map1.put(DateFormatUtils.format(n.getTime(),date),n.getDirectR().floatValue());
        }else if(dataType.equals("散射辐射")){
          map1.put(DateFormatUtils.format(n.getTime(),date),n.getDiffuseR().floatValue());
        }else if(dataType.equals("斜面辐射")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getObliqueR().floatValue());
        }else if(dataType.equals("环境温度")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getAirT().floatValue());
        }else if(dataType.equals("气压")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getP().floatValue());
        }else if(dataType.equals("湿度")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getRh().floatValue());
        }else if(dataType.equals("光伏电池板温度")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getCellT().floatValue());
        }else if(dataType.equals("风速")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getWs().floatValue());
        }else if(dataType.equals("风向")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getWd().floatValue());
        }else if(dataType.equals("日照小时数")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getHourDA().floatValue());
        }else if(dataType.equals("总辐射日累计")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getGlobalRDA().floatValue());
        }else if(dataType.equals("直接辐射日累计")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getDirectRDA().floatValue());
        }else if(dataType.equals("斜面辐射日累计")) {
          map1.put(DateFormatUtils.format(n.getTime(), date), n.getObliqueRDA().floatValue());
        }
        beforeFormatting.add(map1);
      }
      afterFormatting = beforeFormatting.stream().flatMap(m -> m.entrySet().stream()).collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

      //排序
      Map<String, List<Float>> resultMap = new LinkedHashMap<>();
      afterFormatting.entrySet().stream()
        .sorted(Map.Entry.<String, List<Float>>comparingByKey()).forEachOrdered(e -> resultMap.put(e.getKey(), e.getValue()));
      //遍历集合计算出每个时间段集合的最大值、最小值，平均值
      for (String key : resultMap.keySet()) {

        List<Float> v = resultMap.get(key);

        Float maxValue = Collections.max(v);
        Float minValue = Collections.min(v);
        Float init = 0f;
        BigDecimal sum = new BigDecimal(init);
        for (int j = 0;j<v.size();j++){
          BigDecimal value = new BigDecimal(v.get(j));
          sum = sum.add(value);
        }
        BigDecimal size = new BigDecimal(v.size());
        BigDecimal avgValue = sum.divide(size,4,BigDecimal.ROUND_HALF_UP);
        Map<String,Object> map2 = new HashMap<>();
        map2.put("time",key);
        map2.put("maxValue",maxValue);
        map2.put("avgValue",avgValue);
        map2.put("minValue",minValue);
        dataList.add(map2);
      }

    return dataList;
  }


}
