package com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSON;
import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
import com.jiayue.ipfcst.common.data.constant.enums.TunnelStatus;
import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
import com.jiayue.ipfcst.common.data.entity.WeatherStationStatusData;
import com.jiayue.ipfcst.common.data.entity.WindTowerStatusData;
import com.jiayue.ipfcst.console.service.SysParameterService;
import com.jiayue.ipfcst.dataexchange.container.ProtocolTunnelContainer;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.service.EnvironmentDataAnyTimeGenerator;
import com.jiayue.ipfcst.dataexchange.service.EnvironmentDataGenerator;
import com.jiayue.ipfcst.dataexchange.service.FileParseTunnelService;
import com.jiayue.ipfcst.dataexchange.service.GetDataService;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.InverterStatusDataService;
import com.jiayue.ipfcst.dataexchange.tunnelworker.BaseProtocolTunnel;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 带有逆向注入数据功能的数据包装类
 *
 * @author: xiuwei
 * @version:
 */
@Slf4j
public class EquipmentDataPackerWithReverseInjection<T extends AbstractEquipmentStatusData> extends EquipmentDataPacker<T> {


  /**
   * 需要监听的通道嗯呢
   */
  String tunnelId;

  /**
   * 获取系统参数
   */
  SysParameterService sysParameterService = SpringContextHolder.getBean(SysParameterService.class);


  /**
   * 获取系统参数
   */
  EnvironmentDataAnyTimeGenerator environmentDataGenerator = SpringContextHolder.getBean(EnvironmentDataAnyTimeGenerator.class);

  /**
   * 构造方法，在方法中获取传入类型的属性，存入map中，以便后期使用
   *
   * @param newInstance T的实例 直接new 对象（）；
   * @param pointList   点表集合
   */
  public EquipmentDataPackerWithReverseInjection(T newInstance, String tunnelId, List<ProtocolGatherDataPoint> pointList) {
    super(newInstance, pointList);
    this.tunnelId = tunnelId;
  }


  /**
   * 通过反射机制将容器中的数据封装入设备描述的实体类 同时对数据合理性进行校验 仅对数据类型为BigDecimal的数据进行合理性校验
   *
   * @return AbstractEquipmentData 设备状态数据
   * @throws DataExchangeException 异常
   */
  @Override
  public synchronized T packageData() throws DataExchangeException {
    if (getPointList() == null || getPointList().size() == 0 || this.tunnelId==null) {
      return getFakeDateBasedOnForecast();
    } else {
      BaseProtocolTunnel tunnel = ProtocolTunnelContainer.getInstance().getTunnel(this.tunnelId);
      TunnelStatus fileParseTunnelStatus = SpringContextHolder.getBean(FileParseTunnelService.class).getFileParseTunnelStatus(this.tunnelId);
      //不需要生成假数据
      boolean flag = false;
      if ("1".equals(sysParameterService.getSysParameter("qzsyycqx", "0"))||(tunnel == null && fileParseTunnelStatus == null)) {
        //协议通道和文件解析通道均无该通道
        //需要生成假数据
        log.info("根据配置生成假数据");
        flag = true;
      } else if (tunnel == null) {
        //如果 协议通道中没有  但是文件解析通道有
        if (fileParseTunnelStatus == TunnelStatus.LOSECONN) {
          //而且文件解析通道处于失去连接状态
          //需要生成假数据
          log.info("{}-通道状态:{}",tunnel.getTunnelId(),tunnel.getTunnelStatus());
          flag = true;
        }
      } else if (!TunnelStatus.CORRECT_STATUS.contains(tunnel.getTunnelStatus())) {
        //如果协议通道的状态既不是网口连接状态 又不是串口监听成功状态
        log.info("{}-通道状态:{}",tunnel.getTunnelId(),tunnel.getTunnelStatus());
        flag = true;
      }
      if (flag) {
        log.info("使用预测气象生成环境数据");
        //当通道没有建立（创建时发生异常或未启用） 或者当通道状态处于非正常连接状态时 获取数据并进行反向注入
        T t = getFakeDateBasedOnForecast();
        for (Map.Entry<ProtocolGatherDataPoint, Field> e : getPoint2FiledMap().entrySet()) {
          try {
            if (BigDecimal.class.equals(e.getValue().getType())) {
              getProtocolDataContainer().putNumber(e.getKey().getId(), (BigDecimal) e.getValue().get(t));
            } else if (Integer.class.equals(e.getValue().getType())) {
              getProtocolDataContainer().putNumber(e.getKey().getId(), BigDecimal.valueOf((Integer) e.getValue().get(t)));
            }
          } catch (IllegalAccessException e1) {
            e1.printStackTrace();
            log.error("反向注入包装类，反向注数据时发生异常");
          }
        }
      }
      return super.packageData();
    }

  }


  /**
   * 获取到根据预测数据生成的假数据
   *
   * @return {@link T}
   */
  public T getFakeDateBasedOnForecast() {
    GetDataService getDataService = SpringContextHolder.getBean(GetDataService.class);
    T t = getT();
    if (t instanceof WindTowerStatusData) {
      //测风塔
      t = (T) environmentDataGenerator.getWindTowerDataGenerator(getEquipmentNo()).generateWindTowerData();
      log.info("测风塔" + getEquipmentNo() + "由于通道或配置原因使用预测数据生成的实时数据");
      log.info("测风塔" + getEquipmentNo() + "生成的假数据：" +((WindTowerStatusData) t).iToString());
    } else if (t instanceof WeatherStationStatusData) {
      t = (T) getDataService.getWeatherStationStatusData(getEquipmentNo(), DateTime.now().toJdkDate());
      log.info("气象站" + getEquipmentNo() + "由于通道或配置原因使用预测数据生成的实时数据");
      log.info("气象站" + getEquipmentNo() + "生成的假数据：" + JSON.toJSONString(t));
    }
    return t;
  }
}
