package com.jiayue.ipfcst.dataexchange.service;

import com.jiayue.ipfcst.common.data.abst.equipmentinfo.AbstractEquipmentInfo;
import com.jiayue.ipfcst.common.data.constant.enums.DataSourceEnum;
import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
import com.jiayue.ipfcst.common.data.constant.enums.TunnelType;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.console.service.ElectricFieldService;
import com.jiayue.ipfcst.console.service.SysParameterService;
import com.jiayue.ipfcst.dataexchange.container.DataPackerContainer;
import com.jiayue.ipfcst.dataexchange.container.ProtocolDataContainer;
import com.jiayue.ipfcst.dataexchange.container.ProtocolTunnelContainer;
import com.jiayue.ipfcst.dataexchange.container.RecurringTaskContainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.WeatherStationStatusDataFilter;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.TheoreticalPowerByHubSpeedCalculateFactory;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml.EquipmentDataPacker;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml.EquipmentDataPackerWithReverseInjection;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml.PowerStationDataPacker;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml.PowerStationDataPackerOne;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.EquipmentInfoService;
import com.jiayue.ipfcst.dataexchange.tunnelworker.workassist.TunnelBuilder;
import com.jiayue.ipfcst.fileupload.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;

/**
 * 启动成功后自动运行
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
@Component
@Slf4j
public class RunAfterStarted implements ApplicationRunner {


  private final
  TunnelInfoService tunnelInfoService;

  private final
  ProtocolGatherDataPointService protocolDataPointService;

  private final
  SimpMessagingTemplate simpMessagingTemplate;

  private final EquipmentInfoService equipmentInfoService;

  private final ElectricFieldService electricFieldService;

  private final SysParameterService sysParameterService;
  private final WeatherStationStatusDataFilter weatherStationStatusDataFilter;

  private final PowerStationDataPacker powerStationDataPacker;

  private final PowerStationDataPackerOne powerStationDataPackerOne;

  private final FileParseTunnelService fileParseTunnelService;

  private final EquipmentStatisticalDataCalculatorService equipmentStatisticalDataCalculatorService;

  /**
   * 在 spring 启动后执行
   *
   * @param tunnelInfoService                         通道信息操作类
   * @param protocolDataPointService                  采集点表操作类
   * @param equipmentAttributeService                 设备属性操作；类
   * @param simpMessagingTemplate                     socket 通讯模版
   * @param equipmentInfoService                      设备信息操作类
   * @param electricFieldService                      电场数据操作类
   * @param sysParameterService
   * @param weatherStationStatusDataFilter
   * @param powerStationDataPacker                    场站数据组装器
   * @param powerStationDataPackerOne
   * @param fileParseTunnelService                    文件解析服务
   * @param equipmentStatisticalDataCalculatorService 设备的数据统计数据的计算器服务
   */
  public RunAfterStarted(TunnelInfoService tunnelInfoService, ProtocolGatherDataPointService protocolDataPointService, EquipmentAttributeService equipmentAttributeService, SimpMessagingTemplate simpMessagingTemplate, EquipmentInfoService equipmentInfoService, ElectricFieldService electricFieldService, SysParameterService sysParameterService, WeatherStationStatusDataFilter weatherStationStatusDataFilter, PowerStationDataPacker powerStationDataPacker, PowerStationDataPackerOne powerStationDataPackerOne, FileParseTunnelService fileParseTunnelService, EquipmentStatisticalDataCalculatorService equipmentStatisticalDataCalculatorService) {
    this.tunnelInfoService = tunnelInfoService;
    this.protocolDataPointService = protocolDataPointService;
    this.simpMessagingTemplate = simpMessagingTemplate;
    this.equipmentInfoService = equipmentInfoService;
    this.electricFieldService = electricFieldService;
    this.sysParameterService = sysParameterService;
    this.weatherStationStatusDataFilter = weatherStationStatusDataFilter;
    this.powerStationDataPacker = powerStationDataPacker;
    this.powerStationDataPackerOne = powerStationDataPackerOne;
    this.fileParseTunnelService = fileParseTunnelService;
    this.equipmentStatisticalDataCalculatorService = equipmentStatisticalDataCalculatorService;
  }

  public static void write2File(String path, String fileName, String context) throws IOException {
    File directory = new File(path);
    if (!directory.exists()) {
      directory.mkdirs();
    }
    File file = new File(path + "/" + fileName);
    if (!file.exists()) {
      try {
        file.createNewFile();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    PrintStream stream = new PrintStream(file);
    stream.print(context);
    stream.flush();
    stream.close();
  }

  /**
   * 查询出数据库内所有通道以及它们负责采集的点位
   * 查询出所有设备的所需的点位  构建他们专属的DataPacker
   * 构建出定时任务
   **/
  @Override
  public void run(ApplicationArguments args) throws Exception {
    //获取所有的通道信息并创建通道
    buildAllTunnel();
    buildAllDataPacker();
    //暂停写入实时数据任务
    // addPushSocketTask();
    fileParseTunnelService.reBuildPoints();
    buildAllStatisticalDataCalculator();
  }

  private void buildAllStatisticalDataCalculator() {
    RecurringTaskContainer.getInstance().addRecurringTask(60, "计算设备状态数据的统计数据", () -> {
      equipmentStatisticalDataCalculatorService.updateAndSaveData();
      return null;
    });
  }

  /**
   * 创建所有的通道
   */
  private void buildAllTunnel() {
    log.info("开始创建协议通道");
    List<BaseTunnelInfo> tunnels = tunnelInfoService.getAllTunnel();
    for (BaseTunnelInfo tunnel : tunnels) {
      if (tunnel.getIsEnable() && !TunnelType.FILEPARSE.equals(tunnel.getTunnelType())) {
        try {
          TunnelBuilder.buildTunnel(tunnel).startTunnel();
          Thread.sleep(3000L);
        } catch (Exception e) {
          log.error("创建通道{}时发生异常", tunnel.getTunnelName(), e);
        }
      }
    }
  }

  /**
   * 创建所有的数据包装类
   */
  private void buildAllDataPacker() {
    log.info("开始创建数据包装类");
    List<AbstractEquipmentInfo> abstractEquipmentInfos = equipmentInfoService.getAllEquipmentInfo();
    List<ProtocolGatherDataPoint> dataPoints;
    EquipmentDataPacker dataPacker;
    for (AbstractEquipmentInfo abstractEquipmentInfo : abstractEquipmentInfos) {
      if (abstractEquipmentInfo.getInterval() != null && abstractEquipmentInfo.getInterval() == 0 && abstractEquipmentInfo.getEquipmentType().getCode()<8) {
        continue;
      }
      dataPoints = protocolDataPointService.getByEquipmentId(abstractEquipmentInfo.getId(), abstractEquipmentInfo.getEquipmentType());
      if (dataPoints.size() > 0 ) {
        switch (abstractEquipmentInfo.getEquipmentType()) {
          case INVERTER:
            dataPacker = new EquipmentDataPacker(new InverterStatusData(), dataPoints);
            break;
          case WINDTURBINE:
            dataPacker = new EquipmentDataPacker(new WindTurbineStatusData(), dataPoints);
            TheoreticalPowerByHubSpeedCalculateFactory.getInstance().addWindTurbine((WindTurbineInfo) abstractEquipmentInfo);
            break;
          case AGC_AVC:
            dataPacker = new EquipmentDataPacker(new AGC_AVCStatusData(), dataPoints);
            break;
          case WINDTOWER: {
            String bindTunnel = ((WindTowerInfo) abstractEquipmentInfo).getBindTunnel();
            if ("1".equals(sysParameterService.getSysParameter("qzsyycqx", "0"))) {
              dataPacker = new EquipmentDataPackerWithReverseInjection(new WindTowerStatusData(), bindTunnel, dataPoints);
            } else {
              if (StringUtils.isEmpty(bindTunnel)) {
                dataPacker = new EquipmentDataPacker(new WindTowerStatusData(), dataPoints);
              } else {
                dataPacker = new EquipmentDataPackerWithReverseInjection(new WindTowerStatusData(), bindTunnel, dataPoints);
              }
            }
          }
          break;
          case WEATHERSTATION: {
            String bindTunnel = ((WeatherStationInfo) abstractEquipmentInfo).getBindTunnel();
            if ("1".equals(sysParameterService.getSysParameter("qzsyycqx", "0"))) {
              log.info("根据系统参数强制使用预测气象数据代替环境数据");
              dataPacker = new EquipmentDataPackerWithReverseInjection(new WeatherStationStatusData(), bindTunnel, dataPoints);
            } else {
              if (StringUtils.isEmpty(bindTunnel)) {
                dataPacker = new EquipmentDataPacker(new WeatherStationStatusData(), dataPoints);
              } else {
                dataPacker = new EquipmentDataPackerWithReverseInjection(new WeatherStationStatusData(), bindTunnel, dataPoints);
              }
            }
            weatherStationStatusDataFilter.addFilters(dataPoints);
          }
          break;
          default:
            for (ProtocolGatherDataPoint p : dataPoints) {
                if(DataSourceEnum.GENERATE==p.getDataSource()){
                  ProtocolDataContainer.getInstance().addCalculator(p);
                }
            }
            continue;
        }
        if (abstractEquipmentInfo.getInterval() != null && abstractEquipmentInfo.getInterval() > 2) {
          dataPacker.setInterval(abstractEquipmentInfo.getInterval());
        }
        DataPackerContainer.getInstance().addPacker(abstractEquipmentInfo.getEquipmentType().getMessage() + "-" + abstractEquipmentInfo.getId(), dataPacker);
      }
    }
    //添加场站的数据组装器
    DataPackerContainer.getInstance().addPacker(EquipmentTypeEnum.POWERSTATION.getMessage(), powerStationDataPacker.init());
    DataPackerContainer.getInstance().addPacker(EquipmentTypeEnum.POWERSTATION2.getMessage(), powerStationDataPackerOne.init());
  }

  /**
   * 添加socket推送的定时任务
   */
  public void addPushSocketTask() {
    //推送数据池内容
    RecurringTaskContainer.getInstance().addRecurringTask(30, "向websocket推送数据池内容", () -> {
      String s = ProtocolDataContainer.getInstance().toString();
      //  log.info("数据池内容：\n" + ProtocolDataContainer.getInstance().toStringFormatted());
      simpMessagingTemplate.convertAndSend("/data/gatherData", s);
      return null;
    });
    //写入实时文件
    RecurringTaskContainer.getInstance().addRecurringTask(30, "写入实时数据文件", () -> {
      write2File(FileUtil.getLogsPath(), "realTimeData.log", ProtocolDataContainer.getInstance().toStringFormatted());
      return null;
    });
    //推送通道状态信息
    RecurringTaskContainer.getInstance().addRecurringTask(30, "向websocket推送通道状态情况", () -> {
      String s = ProtocolTunnelContainer.getInstance().toString();
      //  log.info("通道状态情况：\n" + ProtocolTunnelContainer.getInstance().toStringFormatted());
      simpMessagingTemplate.convertAndSend("/tunnel/tunnelStatus", s);
      return null;
    });

  }

}
