package com.jiayue.ipfcst.fileupload.service;

import com.jiayue.ipfcst.common.core.util.DateTimeUtil;
import com.jiayue.ipfcst.common.data.constant.enums.*;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.common.data.repository.ReportWindTowerStatusDataRepository;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogRepository;
import com.jiayue.ipfcst.common.data.service.BaseService;

import com.jiayue.ipfcst.dataexchange.container.DataPackerContainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.AbstractDataPacker;
import com.jiayue.ipfcst.dataexchange.service.EnvironmentDataAnyTimeGenerator;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.WindTowerStatusDataService;
import com.jiayue.ipfcst.fileupload.util.FileConstant;
import com.jiayue.ipfcst.fileupload.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 上报文件生成基础类
 *
 * @author xsl
 * @version 3.0
 */

@Service
@Slf4j
public abstract class BaseUploadFileService extends BaseService {
  @Autowired
  private UploadFileLogRepository uploadFileLogRepository;
  @Autowired
  private UploadObjectService uploadObjectService;
  @Autowired
  UploadFileChannelService uploadFileChannelService;
  @Autowired
  EnvironmentDataAnyTimeGenerator environmentDataAnyTimeGenerator;
  @Autowired
  WindTowerStatusDataService windTowerStatusDataService;
  @Autowired
  ReportWindTowerStatusDataRepository reportWindTowerStatusDataRepository;


  /**
   * 复制上报文件到上报路径
   *
   * @param file              需要上报的文件
   * @param fileType          文件类型
   * @param uploadFileEndTime 上报文件截止时间
   */
  @Transactional(propagation = Propagation.REQUIRED)
  protected void copyFileToUploadDir(File file, String fileType, Long uploadFileEndTime) {
    String destFileDir = null;

    try {
      // 获取上报对象
      List<UploadObject> uploadObjectList = uploadObjectService.get();
      if (uploadObjectList.isEmpty()) {
        // 没有有效上报通道进行告警
        String errorInfo = "文件生成没有上报对象可用";
        String name = file.getName() + "生成失败";
        String describe = FileTypeEnum.valueOf(fileType).getMessage();
        String solution = "请配置相关上报对象";
        super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
      } else {
        // 遍历上报对象生成对应的文件
        for (UploadObject uploadObject : uploadObjectList) {
          List<UploadFileChannel> uploadFileChannelList = uploadFileChannelService.getByObjectId(uploadObject.getId());
          // 找出对象下是否有可用的通道
          List<UploadFileChannel> filterUploadFileChannelList = uploadFileChannelList.stream().filter(s -> "E1".equals(s.getChannelStatusEnum().toString())).collect(Collectors.toList());
          if (filterUploadFileChannelList.size() > 0) {
            String[] uploadFileType = uploadObject.getUploadFileType().split(",");
            for (int k = 0; k < uploadFileType.length; k++) {
              if (uploadFileType[k].equals(fileType)) {
                // 上报文件目录
                destFileDir = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + uploadObject.getObjectNo() + File.separator + fileType;
                File destDir = new File(destFileDir);
                if (!destDir.exists()) {// 如果目录不存在则创建uploadFileEndTime目录
                  boolean b = destDir.mkdirs();
                  if (!b) // 如果创建失败则抛出异常
                    throw new RuntimeException(destFileDir + " 目录创建失败");
                }
                if (!new File(destDir + File.separator + file.getName()).exists()) {
                  FileUtils.copyFileToDirectory(file, destDir);
                  UploadFileLog uploadFileLog = new UploadFileLog();
                  uploadFileLog.setUploadObjectId(uploadObject.getId());
                  uploadFileLog.setUploadObjectName(uploadObject.getUploadObjectName());
                  uploadFileLog.setUploadObjectNo(uploadObject.getObjectNo());
                  uploadFileLog.setFileName(file.getName());
                  uploadFileLog.setFileTypeEnum(FileTypeEnum.valueOf(fileType));
                  uploadFileLog.setFileStatusEnum(FileStatusEnum.E1);
                  uploadFileLog.setUploadProtocolEnum(uploadObject.getUploadProtocolEnum());
                  uploadFileLog.setUploadCounter(0);
                  uploadFileLog.setUploadFileEndTime(uploadFileEndTime);

                  uploadFileLog = this.uploadFileLogRepository.save(uploadFileLog);

                  String readyFileKey = uploadObject.getObjectNo() + "@" + fileType + "@" + file.getName();
                  FileConstant.fileShouldMomentMap.put(readyFileKey, uploadFileLog.getId());
                  FileConstant.readyUploadFileMap.put(readyFileKey, uploadFileLog);

                  log.debug("文件生成存入缓存：" + file.getName());
                  log.info("上报对象编号：" + uploadObject.getObjectNo() + ",生成文件" + file.getName() + "成功");
                } else {
                  log.info("本地文件已经生成，上报对象编号：" + uploadObject.getObjectNo() + "," + file.getName() + "不再生成了");
                }
                break;
              }
            }
          }
        }
      }
    } catch (Exception e) {
      // 文件复制失败进行告警
      String errorInfo = "复制文件[" + file.getName() + "]到上报目录[" + destFileDir + "]失败";
      log.error(errorInfo, e);
      // 进行告警
      String name = file.getName() + "生成失败";
      String describe = FileTypeEnum.valueOf(fileType).getMessage();
      String solution = "请查看日志异常信息";
      super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
    }
  }


  /**
   * 复制上报文件到上报路径（补报）
   *
   * @param file              需要上报的文件
   * @param fileType          文件类型
   * @param uploadFileEndTime 上报文件截止时间
   */
  @Transactional(propagation = Propagation.REQUIRED)
  protected void copyFileToUploadDirBB(File file, String fileType, Long uploadFileEndTime, Date createTime) {
    String destFileDir = null;

    try {
      // 获取上报对象
      List<UploadObject> uploadObjectList = uploadObjectService.get();
      if (uploadObjectList.isEmpty()) {
        // 没有有效上报通道进行告警
        String errorInfo = "文件生成没有上报对象可用";
        String name = file.getName() + "生成失败";
        String describe = FileTypeEnum.valueOf(fileType).getMessage();
        String solution = "请配置相关上报对象";
        super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
      } else {
        List<UploadFileLog> uploadFileLogList = uploadFileLogRepository.findByFileNameAndCreateTimeAfterAndFileTypeEnum(file.getName(), createTime,FileTypeEnum.valueOf(fileType));
        for (UploadFileLog uploadFileLog : uploadFileLogList) {
          uploadObjectList = uploadObjectList.stream().filter(s -> !s.getObjectNo().equals(uploadFileLog.getUploadObjectNo())).collect(Collectors.toList());
        }
        // 遍历上报对象生成对应的文件
        for (UploadObject uploadObject : uploadObjectList) {
          List<UploadFileChannel> uploadFileChannelList = uploadFileChannelService.getByObjectId(uploadObject.getId());
          // 找出对象下是否有可用的通道
          List<UploadFileChannel> filterUploadFileChannelList = uploadFileChannelList.stream().filter(s -> "E1".equals(s.getChannelStatusEnum().toString())).collect(Collectors.toList());
          if (filterUploadFileChannelList.size() > 0) {
            String[] uploadFileType = uploadObject.getUploadFileType().split(",");
            for (int k = 0; k < uploadFileType.length; k++) {
              if (uploadFileType[k].equals(fileType)) {
                // 上报文件目录
                destFileDir = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + uploadObject.getObjectNo() + File.separator + fileType;
                File destDir = new File(destFileDir);
                if (!destDir.exists()) {// 如果目录不存在则创建uploadFileEndTime目录
                  boolean b = destDir.mkdirs();
                  if (!b) // 如果创建失败则抛出异常
                    throw new RuntimeException(destFileDir + " 目录创建失败");
                }
                if (!new File(destDir + File.separator + file.getName()).exists()) {
                  FileUtils.copyFileToDirectory(file, destDir);
                  UploadFileLog uploadFileLog = new UploadFileLog();
                  uploadFileLog.setUploadObjectId(uploadObject.getId());
                  uploadFileLog.setUploadObjectName(uploadObject.getUploadObjectName());
                  uploadFileLog.setUploadObjectNo(uploadObject.getObjectNo());
                  uploadFileLog.setFileName(file.getName());
                  uploadFileLog.setFileTypeEnum(FileTypeEnum.valueOf(fileType));
                  uploadFileLog.setFileStatusEnum(FileStatusEnum.E1);
                  uploadFileLog.setUploadProtocolEnum(uploadObject.getUploadProtocolEnum());
                  uploadFileLog.setUploadCounter(0);
                  uploadFileLog.setUploadFileEndTime(uploadFileEndTime);
                  uploadFileLog = this.uploadFileLogRepository.save(uploadFileLog);
                  uploadFileLog.setCreateTime(createTime);
                  Date date = new Date();
                  String format = DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss");
                  uploadFileLog.setBackupA(format);
                  uploadFileLog = this.uploadFileLogRepository.save(uploadFileLog);

                  String readyFileKey = uploadObject.getObjectNo() + "@" + fileType + "@" + file.getName();
                  FileConstant.fileShouldMomentMap.put(readyFileKey, uploadFileLog.getId());
                  FileConstant.readyUploadFileMap.put(readyFileKey, uploadFileLog);

                  log.debug("文件生成存入缓存：" + file.getName());
                  log.info("上报对象编号：" + uploadObject.getObjectNo() + ",生成文件" + file.getName() + "成功");
                } else {
                  log.info("本地文件已经生成，上报对象编号：" + uploadObject.getObjectNo() + "," + file.getName() + "不再生成了");
                }
                break;
              }
            }
          }
        }
      }
    } catch (Exception e) {
      // 文件复制失败进行告警
      String errorInfo = "复制文件[" + file.getName() + "]到上报目录[" + destFileDir + "]失败";
      log.error(errorInfo, e);
      // 进行告警
      String name = file.getName() + "生成失败";
      String describe = FileTypeEnum.valueOf(fileType).getMessage();
      String solution = "请查看日志异常信息";
      super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
    }
  }

  /**
   * 查詢文件是否生成
   *
   * @param fileName
   * @return 存在则返回false，不存在返回true
   */
  @Transactional(propagation = Propagation.REQUIRED)
  protected boolean getFileName(String fileName, String fileType) {
    int cdqUpMin = getTranSysParameter("CDQ_UP_MIN", "0");
    //今日凌晨
    Long jt = DateTimeUtil.getMillisecondsSubDay() - (15 * 60 * 1000 + cdqUpMin * 1000 * 60);
    //明日凌晨
    Long mt = DateTimeUtil.getMillisecondsSubDay() + 1000 * 60 * 60 * 24;

    List<UploadObject> uploadObjectList = uploadObjectService.get();

    List<UploadFileChannel> uploadFileChannelList = uploadFileChannelService.get();

    List<UploadFileChannel> uploadFileChannels = uploadFileChannelList.stream().filter(s -> s.getChannelStatusEnum().getCode().toString().equals("1")).collect(Collectors.toList());
    int n = 0;
    for (UploadObject uploadObject : uploadObjectList) {
      List<UploadFileChannel> collect = uploadFileChannels.stream().filter(s -> s.getUploadObjectId() == uploadObject.getId()).collect(Collectors.toList());
      if(collect.size()>0){
        String[] split = uploadObject.getUploadFileType().split(",");
        for (int i = 0; i < split.length; i++) {
          if (split[i].equals(FileTypeEnum.valueOf(fileType).toString())) {
            n++;
            break;
          }
        }
      }
    }

    List<UploadFileLog> list = this.uploadFileLogRepository.findByFileNameAndFileTypeEnumAndCreateTimeBetween(fileName, FileTypeEnum.valueOf(fileType), new Date(jt), new Date(mt));
    if (null != list && list.size() >= n) {
      return false;
    } else {
      return true;
    }
  }

  /**
   * 创建临时文件
   *
   * @param fileName 文件名
   * @return 临时文件
   */
  protected File createTempFile(String fileName) {
    // 获取临时目录
    String tempDir = FileUtil.getTempFilePath() + File.separator + UUID.randomUUID().toString().replace("-", "");
    boolean b = new File(tempDir).mkdir();
    if (!b) {
      throw new RuntimeException("创建文件" + fileName + "失败");
    }
    File file = new File(tempDir + File.separator + fileName);
    try {
      b = file.createNewFile();
      if (!b)
        throw new RuntimeException("创建文件" + fileName + "失败");
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return file;
  }

  /**
   * 获取文件上报数值类型参数
   *
   * @param key
   * @param defaultValue
   * @return
   */
  protected int getTranSysParameter(String key, String defaultValue) {
    int returnValue = 0;
    try {
      String value = super.getSysParameter(key, defaultValue);
      returnValue = Integer.parseInt(value);
    } catch (RuntimeException e) {
      String errorInfo = "参数表" + key + "获取失败";
      log.error(errorInfo, e);
      String name = "参数表" + key + "获取失败";
      String describe = "参数表" + key + "获取失败";
      String solution = "使用默认值" + defaultValue;
      super.saveSysAlarm(AlarmTypeEnum.E1, name, describe, errorInfo, solution);
      returnValue = Integer.parseInt(defaultValue);
    }
    return returnValue;
  }

  /**
   * 生成上报文件
   *
   * @param writer
   * @param file
   * @param fileType
   * @param uploadFileEndTime
   */
  protected void copyUploadFile(StringWriter writer, File file, String fileType, Long uploadFileEndTime, Date createTime) {
    FileOutputStream os = null;
    try {
      os = new FileOutputStream(file);
      // 采用UTF-8字符集
      os.write(writer.toString().getBytes("UTF-8"));
      os.flush();
      if (createTime == null) {
        // 将文件复制到上报路径中
        copyFileToUploadDir(file, fileType, uploadFileEndTime);
      } else {
        copyFileToUploadDirBB(file, fileType, uploadFileEndTime, createTime);
      }

    } catch (IOException e) {
      throw new RuntimeException(e);
    } finally {
      if (os != null) {
        try {
          os.close();
        } catch (IOException e) {
          log.error("文件生成关闭流失败", e);
        }
      }
      try {
        FileUtils.forceDelete(file.getParentFile());
      } catch (IOException e) {
        log.error("", e);
      }
    }
  }



  protected void justCopyUploadFile(File file, String fileType, Long uploadFileEndTime, Date createTime) {

    try {

      if (createTime == null) {
        // 将文件复制到上报路径中
        copyFileToUploadDir(file, fileType, uploadFileEndTime);
      } else {
        copyFileToUploadDirBB(file, fileType, uploadFileEndTime, createTime);
      }

    } finally {
      try {
        FileUtils.forceDelete(file.getParentFile());
      } catch (IOException e) {
        log.error("", e);
      }
    }
  }


  /**
   * 获取池子中的设备值替代原有的从数据库中取值
   *
   * @return
   */
  public PowerStationStatusData getPowerStationStatusData() {
    try {

      if (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.POWERSTATION.getMessage()) == null) {
        return null;
      }
      AbstractDataPacker<PowerStationStatusData> powerStationStatusDataAbstractDataPacker = (AbstractDataPacker<PowerStationStatusData>) (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.POWERSTATION.getMessage()));
      return powerStationStatusDataAbstractDataPacker.packageData();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 获取池子中的设备值替代原有的从数据库中取值
   *
   * @param id 设备id
   * @return
   */
  public WindTowerStatusData getWindTowerStatusData(Integer id) {
    try {

      if (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WINDTOWER.getMessage() + "-" + id) == null) {
        return null;
      }
      if (!windTowerStatusDataService.getIsAbnormalData()){
        AbstractDataPacker<WindTowerStatusData> windTowerStatusDataPacker = (AbstractDataPacker<WindTowerStatusData>) (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WINDTOWER.getMessage() + "-" + id));
        return windTowerStatusDataPacker.packageData();
      }else {
        return environmentDataAnyTimeGenerator.getWindTowerDataGenerator(id).generateWindTowerData();
      }
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }

  }


  /**
   * 获取池子中的设备值替代原有的从数据库中取值
   *
   * @param id 设备id
   * @return
   */
  public WindTurbineStatusData getWindTurbineStatusData(Integer id) {
    try {

      if (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WINDTURBINE.getMessage() + "-" + id) == null) {
        return null;
      }
      AbstractDataPacker<WindTurbineStatusData> windTurbineStatusDataPacker = (AbstractDataPacker<WindTurbineStatusData>) (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WINDTURBINE.getMessage() + "-" + id));
      return windTurbineStatusDataPacker.packageData();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 获取池子中的设备值替代原有的从数据库中取值
   *
   * @param id 设备id
   * @return
   */
  public WeatherStationStatusData getWeatherStationStatusData(Integer id) {
    try {

      if (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WEATHERSTATION.getMessage() + "-" + id) == null) {
        return null;
      }
      AbstractDataPacker<WeatherStationStatusData> weatherStationStatusDataPacker = (AbstractDataPacker<WeatherStationStatusData>) (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.WEATHERSTATION.getMessage() + "-" + id));
      return weatherStationStatusDataPacker.packageData();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 获取池子中的设备值替代原有的从数据库中取值
   *
   * @param id 设备id
   * @return
   */
  public InverterStatusData getInverterStatusData(Integer id) {
    try {

      if (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.INVERTER.getMessage() + "-" + id) == null) {
        return null;
      }
      AbstractDataPacker<InverterStatusData> InverterStatusDataPacker = (AbstractDataPacker<InverterStatusData>) (DataPackerContainer.getInstance().getPacker(EquipmentTypeEnum.INVERTER.getMessage() + "-" + id));
      return InverterStatusDataPacker.packageData();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 存入上报测风塔数据
   *
   * @param reportWindTowerStatusData 测风塔数据实体
   * @return
   */

  public void saveReportWindTowerStatusData(ReportWindTowerStatusData reportWindTowerStatusData) {
    reportWindTowerStatusDataRepository.deleteAllByTime(reportWindTowerStatusData.getTime());
    reportWindTowerStatusDataRepository.save(reportWindTowerStatusData);
  }


  /**
   * 转换实时测风数据为上报测风数据
   *
   * @param windTowerStatusData 数据集合
   * @return
   */
  public ReportWindTowerStatusData transReportWindTowerStatusData(WindTowerStatusData windTowerStatusData) {
    ReportWindTowerStatusData reportWindTowerStatusData = new ReportWindTowerStatusData();
    reportWindTowerStatusData.setTime(windTowerStatusData.getTime());
    reportWindTowerStatusData.setWs10(windTowerStatusData.getWsInst10());
    reportWindTowerStatusData.setWd10(windTowerStatusData.getWdInst10());
    reportWindTowerStatusData.setWs30(windTowerStatusData.getWsInst30());
    reportWindTowerStatusData.setWd30(windTowerStatusData.getWdInst30());
    reportWindTowerStatusData.setWs50(windTowerStatusData.getWsInst50());
    reportWindTowerStatusData.setWd50(windTowerStatusData.getWdInst50());
    reportWindTowerStatusData.setWs60(windTowerStatusData.getWsInst60());
    reportWindTowerStatusData.setWd60(windTowerStatusData.getWdInst60());
    reportWindTowerStatusData.setWs70(windTowerStatusData.getWsInst70());
    reportWindTowerStatusData.setWd70(windTowerStatusData.getWdInst70());
    reportWindTowerStatusData.setWs80(windTowerStatusData.getWsInst80());
    reportWindTowerStatusData.setWd80(windTowerStatusData.getWdInst80());
    reportWindTowerStatusData.setWs90(windTowerStatusData.getWsInst90());
    reportWindTowerStatusData.setWd90(windTowerStatusData.getWdInst90());
    reportWindTowerStatusData.setWs100(windTowerStatusData.getWsInst100());
    reportWindTowerStatusData.setWd100(windTowerStatusData.getWdInst100());
    reportWindTowerStatusData.setWs110(windTowerStatusData.getWsInst110());
    reportWindTowerStatusData.setWd110(windTowerStatusData.getWdInst110());
    reportWindTowerStatusData.setWs120(windTowerStatusData.getWsInst120());
    reportWindTowerStatusData.setWd120(windTowerStatusData.getWdInst120());
    reportWindTowerStatusData.setWsHubHeight(windTowerStatusData.getWsInstHubHeight());
    reportWindTowerStatusData.setWdHubHeight(windTowerStatusData.getWdInstHubHeight());
    reportWindTowerStatusData.setT(windTowerStatusData.getTInst());
    reportWindTowerStatusData.setPa(windTowerStatusData.getPaInst());
    reportWindTowerStatusData.setRh(windTowerStatusData.getRhInst());
    reportWindTowerStatusData.setAirDensity(windTowerStatusData.getAirDensity());

    return reportWindTowerStatusData;
  }

}
