package com.jiayue.ipfcst.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ReflectUtil;
import com.jiayue.ipfcst.common.core.exception.BusinessException;
import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.common.data.repository.*;
import com.jiayue.ipfcst.common.data.service.BaseService;
import com.jiayue.ipfcst.repository.CustomReportFormRepository;
import com.jiayue.ipfcst.repository.EquipmentAttributeRepository;
import com.jiayue.ipfcst.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CustomReportFormService extends BaseService {
  private final CustomReportFormRepository customReportFormRepository;
  private final EquipmentAttributeRepository equipmentAttributeRepository;
  private final WeatherStationInfoRepository weatherStationInfoRepository;
  private final WindTowerInfoRepository windTowerInfoRepository;
  private final ForecastPowerShortTermHisRepository forecastPowerShortTermHisRepository;
  private final ForecastPowerUltraShortTermHisRepository forecastPowerUltraShortTermHisRepository;
  private final PowerStationStatusDataRepository powerStationStatusDataRepository;
  private final WeatherStationStatusDataRepository weatherStationStatusDataRepository;
  private final WindTowerStatusDataRepository windTowerStatusDataRepository;
  private final NwpHisRepository nwpHisRepository;
  private final ProtocolGatherDataPointService protocolGatherDataPointService;

  private final static Map<String, String> NWP_MAP = new HashMap<>();

  static {
    NWP_MAP.put("t", "温度");
    NWP_MAP.put("rh", "湿度");
    NWP_MAP.put("pressure", "气压");
    NWP_MAP.put("swr", "辐射");
    NWP_MAP.put("lwr", "短波辐射");
    NWP_MAP.put("directRadiation", "直辐射");
    NWP_MAP.put("diffuseRadiation", "散辐射");
    NWP_MAP.put("senf", "热感通量");
    NWP_MAP.put("ws10", "10米风速");
    NWP_MAP.put("ws30", "30米风速");
    NWP_MAP.put("ws50", "50米风速");
    NWP_MAP.put("ws70", "70米风速");
    NWP_MAP.put("ws80", "80米风速");
    NWP_MAP.put("ws90", "90米风速");
    NWP_MAP.put("ws100", "100米风速");
    NWP_MAP.put("ws170", "170米风速");
    NWP_MAP.put("wd10", "10米风向");
    NWP_MAP.put("wd30", "30米风向");
    NWP_MAP.put("wd50", "50米风向");
    NWP_MAP.put("wd70", "70米风向");
    NWP_MAP.put("wd80", "80米风向");
    NWP_MAP.put("wd90", "90米风向");
    NWP_MAP.put("wd100", "100米风向");
    NWP_MAP.put("wd170", "170米风向");
  }

  @Autowired
  public CustomReportFormService(CustomReportFormRepository customReportFormRepository,
                                 EquipmentAttributeRepository equipmentAttributeRepository,
                                 WeatherStationInfoRepository weatherStationInfoRepository,
                                 WindTowerInfoRepository windTowerInfoRepository,
                                 ForecastPowerShortTermHisRepository forecastPowerShortTermHisRepository,
                                 ForecastPowerUltraShortTermHisRepository forecastPowerUltraShortTermHisRepository,
                                 PowerStationStatusDataRepository powerStationStatusDataRepository,
                                 WeatherStationStatusDataRepository weatherStationStatusDataRepository,
                                 WindTowerStatusDataRepository windTowerStatusDataRepository,
                                 NwpHisRepository nwpHisRepository,
                                 ProtocolGatherDataPointService protocolGatherDataPointService) {
    this.customReportFormRepository = customReportFormRepository;
    this.equipmentAttributeRepository = equipmentAttributeRepository;
    this.weatherStationInfoRepository = weatherStationInfoRepository;
    this.windTowerInfoRepository = windTowerInfoRepository;
    this.forecastPowerShortTermHisRepository = forecastPowerShortTermHisRepository;
    this.forecastPowerUltraShortTermHisRepository = forecastPowerUltraShortTermHisRepository;
    this. powerStationStatusDataRepository = powerStationStatusDataRepository;
    this.weatherStationStatusDataRepository = weatherStationStatusDataRepository;
    this.windTowerStatusDataRepository = windTowerStatusDataRepository;
    this.nwpHisRepository = nwpHisRepository;
    this.protocolGatherDataPointService = protocolGatherDataPointService;

  }

  public void generate() throws BusinessException, InterruptedException {
    List<CustomReportForm> list = customReportFormRepository.findByTimingRealTime("1");
    String filePath = FileUtil.getreportFormPath();
    String fileAllPath = "";
    CsvWriter csvWriter;
    Date yesterday = DateUtil.yesterday();
    Date beginOfDay = DateUtil.beginOfDay(yesterday);
    Date endOfDay = DateUtil.endOfDay(yesterday);
    String dateFormat = DateUtil.format(beginOfDay, "yyyy-MM");
    DateTime dateTime = new DateTime(beginOfDay);
    int day = dateTime.dayOfMonth();

    String eType = this.getElectricField().getElectricFieldTypeEnum().name();
    List<Long> times;
    for (CustomReportForm c : list) {
      List<List<String>> result = new ArrayList<>();
      long startTime = beginOfDay.getTime();
      long endTime = endOfDay.getTime();
      long interval = c.getInterval() * 60000L;
      boolean isUpdate = c.getIsUpdate();
      times = new ArrayList<>();
      for (long i = startTime; i <= endTime; i += interval) {
        times.add(i);
      }
      List<String> timeh = new ArrayList<>();
      if (isUpdate || day == 1) { timeh.add("时间"); }
      for(long time : times){
        String dfm = DateUtil.format(new Date(time), "yyyy-MM-dd HH:mm");
        timeh.add(dfm);
      }
      result.add(timeh);
      fileAllPath = filePath + File.separator + dateFormat + "_" + c.getName() + ".csv";
      csvWriter = CsvUtil.getWriter(fileAllPath, CharsetUtil.CHARSET_UTF_8, true);

      if (c.getDq() != null) {
        List<String> dqResult = new ArrayList<>();
        if (isUpdate|| day == 1) { dqResult.add("短期"); }
        List<ForecastPowerShortTermHis> dq = forecastPowerShortTermHisRepository.findByForecastTimeBetweenAndForecastHowLongAgo(startTime, endTime, c.getDq());
        for (long time : times) {
          List<ForecastPowerShortTermHis> dqFilter = dq.stream().filter(f -> f.getForecastTime() == time).collect(Collectors.toList());
          if (dqFilter != null && dqFilter.size() > 0) {
            dqResult.add(dqFilter.get(0).getAbleValue().toString());
          } else {
            dqResult.add("-99");
          }
        }
        result.add(dqResult);
      }

      if (c.getCdq() != null) {
        List<String> cdqResult = new ArrayList<>();
        if (isUpdate|| day == 1) { cdqResult.add("超短期");}
        List<ForecastPowerUltraShortTermHis> cdq = forecastPowerUltraShortTermHisRepository.findByForecastTimeBetweenAndForecastHowLongAgo(startTime,endTime,c.getCdq());
        for (long time : times) {
          List<ForecastPowerUltraShortTermHis> cdqFilter = cdq.stream().filter(f -> f.getForecastTime() == time).collect(Collectors.toList());
          if (cdqFilter != null && cdqFilter.size() > 0) {
            cdqResult.add(cdqFilter.get(0).getAbleValue().toString());
          } else {
            cdqResult.add("-99");
          }
        }
        result.add(cdqResult);
      }

      if(c.getRp() != null){
        String[] rps = c.getRp().split(",");
        List<PowerStationStatusData> rp = powerStationStatusDataRepository.findByTimeBetween(beginOfDay, endOfDay);
        PowerStationStatusData defaultRp;
        BigDecimal defaultBig = new BigDecimal("-99");
        for (long time : times) {
          List<PowerStationStatusData> rpFilter = rp.stream().filter(r->r.getTime().getTime() == time).collect(Collectors.toList());
          if(rpFilter == null || rpFilter.size()<1){
            defaultRp = new PowerStationStatusData();
            defaultRp.setTime(new Date(time));
            rp.add(defaultRp);
          }
        }

        rp.sort(Comparator.comparing(PowerStationStatusData::getTime));

        for(int i=0;i<rps.length;i++){
          List<String> rpResult = new ArrayList<>();
          if (rps[i].contains("real")) {
            if (isUpdate|| day == 1) { rpResult.add("实际功率");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getRealValue().toString());
            }
          }
          if (rps[i].contains("able")) {
            if (isUpdate || day == 1) { rpResult.add("可用功率");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getAbleValue().toString());
            }
          }
          if (rps[i].contains("theory")) {
            if (isUpdate || day == 1) { rpResult.add("理论功率");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getTheoryValue().toString());
            }
          }
          if (rps[i].contains("openCapacity")) {
            if (isUpdate || day == 1) { rpResult.add("开机容量");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getOpenCapacity().toString());
            }
          }
          if (rps[i].contains("capacity")) {
            if (isUpdate || day == 1) { rpResult.add("装机容量");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getCapacity().toString());
            }
          }
          if (rps[i].contains("onSiteObstructed")) {
            if (isUpdate || day == 1) { rpResult.add("站内受阻");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getOnSiteObstructed().toString());
            }
          }
          if (rps[i].contains("offSiteObstructed")) {
            if (isUpdate || day == 1) { rpResult.add("站外受阻");}
            for(PowerStationStatusData p :rp){
              rpResult.add(p.getOffSiteObstructed().toString());
            }
          }
          result.add(rpResult);
        }
      }

      if(c.getNwp() !=null){
        String[] nwps = c.getNwp().split(",");
        List<NwpHis> nwp = nwpHisRepository.findByPreTimeBetweenAndForecastHowLongAgo(startTime, endTime, Integer.valueOf(nwps[0]));
        NwpHis defaultNwp;

        for(long time:times){
          List<NwpHis> nwpFilter = nwp.stream().filter(n->n.getPreTime() == time).collect(Collectors.toList());
          if(nwpFilter == null || nwpFilter.size()<1){
            defaultNwp = new NwpHis();
            defaultNwp.setPreTime(time);
            nwp.add(defaultNwp);
          }
        }
        nwp.sort(Comparator.comparing(NwpHis::getPreTime));
        for(int i=1;i<nwps.length;i++){
          List<String> nwpResult = new ArrayList<>();
          if (isUpdate|| day == 1) {nwpResult.add("nwp_"+NWP_MAP.get(nwps[i]));}
          for(NwpHis n :nwp){
            String value  = String.valueOf(ReflectUtil.getFieldValue(n, nwps[i]));
            nwpResult.add(value);
          }
          result.add(nwpResult);
        }
      }

      if(c.getEnv() !=null){
        List<EquipmentAttribute> eqAttrList = new ArrayList<>();
        Map<String, String> eqAttrMap = new HashMap<>();
        if (eType.equals("E1")) {
          eqAttrList = equipmentAttributeRepository.findByEquipmentType(EquipmentTypeEnum.WEATHERSTATION);
        } else {
          eqAttrList = equipmentAttributeRepository.findByEquipmentType(EquipmentTypeEnum.WINDTOWER);

        }
        for (EquipmentAttribute e : eqAttrList) {
          eqAttrMap.put(e.getFieldName(), e.getExplanation());
        }

        String[] envEqs = c.getEnv().split("\\|");
        for(int i =0;i<envEqs.length;i++){
          String[] envs = envEqs[i].split(",");
          if(eType.equals("E1")){

            List<WeatherStationStatusData> eqData = weatherStationStatusDataRepository.findByTimeBetweenAndEquipmentNo(beginOfDay, endOfDay, Integer.valueOf(envs[0]));
            WeatherStationStatusData defaultWea;

            for(long time:times){
              List<WeatherStationStatusData> weaFilter = eqData.stream().filter(w -> w.getTime().getTime() == time).collect(Collectors.toList());
              if(weaFilter == null || weaFilter.size()<1){
                defaultWea = new WeatherStationStatusData();
                defaultWea.setTime(new Date(time));
                eqData.add(defaultWea);
              }
            }
            eqData.sort(Comparator.comparing(WeatherStationStatusData::getTime));
            for(int j = 1;j<envs.length;j++){
              List<String> weaResult = new ArrayList<>();
              if (isUpdate|| day == 1) {weaResult.add("env_"+eqAttrMap.get(envs[j]));}
              for(WeatherStationStatusData w:eqData){
                String value = String.valueOf(ReflectUtil.getFieldValue(w,envs[j]));
                weaResult.add(value);
              }
              result.add(weaResult);
            }
          }else{
            List<WindTowerStatusData> eqData = windTowerStatusDataRepository.findByEquipmentNoAndTimeBetween(Integer.valueOf(envs[0]), beginOfDay, endOfDay);
            WindTowerStatusData defaultWin;

            for(long time:times){
              List<WindTowerStatusData> weaFilter = eqData.stream().filter(w -> w.getTime().getTime() == time).collect(Collectors.toList());
              if(weaFilter == null || weaFilter.size()<1){
                defaultWin = new WindTowerStatusData();
                defaultWin.setTime(new Date(time));
                eqData.add(defaultWin);
              }
            }
            eqData.sort(Comparator.comparing(WindTowerStatusData::getTime));
            for(int j = 1;j<envs.length;j++){
              List<String> winResult = new ArrayList<>();
              if (isUpdate|| day == 1) {winResult.add("env_"+eqAttrMap.get(envs[j]));}
              for(WindTowerStatusData w:eqData){
                String value = String.valueOf(ReflectUtil.getFieldValue(w,envs[j]));
                winResult.add(value);
              }
              result.add(winResult);
            }
          }
        }
      }
      int dataLength = times.size();
      if (isUpdate|| day == 1){dataLength++;}
      for(int i = 0;i<dataLength;i++){
        String[] csv = new String[result.size()];
        for(int j =0;j<result.size();j++){
          csv[j] = result.get(j).get(i);
        }
        for(int t=0;t<result.size();t++){
          if(csv[t].equals("-99")){
            csv[t] = "";
          }
        }
        csvWriter.write(csv);
      }
      csvWriter.close();
      c.setIsUpdate(false);
      customReportFormRepository.save(c);

    }

  }

  public CsvWriter isUseOrCreate(String fileAllPath,int c) throws InterruptedException {
    CsvWriter csvWriter = null;
    c++;
    if(c<10){
      try{
        csvWriter = CsvUtil.getWriter(fileAllPath, CharsetUtil.CHARSET_UTF_8, true);
      }catch (Exception e){
        log.info(fileAllPath+"正在被其他程序占用，等待5分钟后继续操作");
        Thread.sleep(1000*30);
        csvWriter = isUseOrCreate(fileAllPath,c);
      }
    }else{
      log.info(fileAllPath+"一直被占用，无法打开。数据插入报表失败");
      return csvWriter;
    }
    return csvWriter;
  }
  /**
   * 根据实时或者定时查询数据
   *
   * @param timingOrRealTime
   * @return
   */
  public List<CustomReportForm> findByTimingOrRealTime(String timingOrRealTime){
    List<CustomReportForm> byTimingRealTimeEquals = customReportFormRepository.findByTimingRealTimeEquals(timingOrRealTime);
    return byTimingRealTimeEquals;

  }

  /**
   * 根据实时或者定时查询数据
   *
   * @param
   * @return
   */
  public List<CustomReportForm> findAll(){
    List<CustomReportForm> byTimingRealTimeEquals = customReportFormRepository.findAll();
    return byTimingRealTimeEquals;

  }

  public List<Map<String,Object>> findEqOptions() throws BusinessException {
    ElectricField electricField = super.getElectricField();
    List<Map<String,Object>> list = new ArrayList<>();
    String equipmentType = "WEATHERSTATION";
    if(electricField.getElectricFieldTypeEnum().getCode()==2){
      equipmentType = "WINDTOWER";
      List<WindTowerInfo> windTowerInfos = windTowerInfoRepository.findAll();
      for (WindTowerInfo windTowerInfo : windTowerInfos) {
        Map<String,Object> map = new HashMap<>();
        map.put("eq",windTowerInfo);
        List<EquipmentAttribute> equipmentAttributes = protocolGatherDataPointService.getEquipmentAttribute(windTowerInfo.getId(), equipmentType);
        map.put("eqf",equipmentAttributes);
        list.add(map);
      }
    }else {
      List<WeatherStationInfo> weatherStationInfos = weatherStationInfoRepository.findAll();
      for (WeatherStationInfo weatherStationInfo : weatherStationInfos) {
        Map<String,Object> map = new HashMap<>();
        map.put("eq",weatherStationInfo);
        List<EquipmentAttribute> equipmentAttributes = protocolGatherDataPointService.getEquipmentAttribute(weatherStationInfo.getId(), equipmentType);
        map.put("eqf",equipmentAttributes);
        list.add(map);
      }
    }

    return list;

  }


  public void save(CustomReportForm customReportForm){
    customReportFormRepository.save(customReportForm);
  }


  public List<EquipmentAttribute> findEquipmentAttributeByEqType(){
    EquipmentTypeEnum equipmentTypeEnum = EquipmentTypeEnum.WEATHERSTATION;
    ElectricField electricField = null;
    try {
      electricField = super.getElectricField();
    }catch (BusinessException e){
      log.error("获取场站信息出错"+e);
    }

    if(electricField!=null&&electricField.getElectricFieldTypeEnum().getCode()==2){
      equipmentTypeEnum = EquipmentTypeEnum.WINDTOWER;
    }
    return  equipmentAttributeRepository.findByEquipmentType(equipmentTypeEnum);
  }

  public void deleteById(Integer id){
    customReportFormRepository.deleteById(id);
  }

}


