package net.northking.cctp.se.lifecycle;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.northking.cctp.se.config.AtuServerConfig;
import net.northking.cctp.se.dto.EngineStatus;
import net.northking.cctp.se.dto.ScriptEngineInfo;
import net.northking.cctp.se.lifecycle.constant.MQConstant;
import net.northking.cctp.se.lifecycle.entity.CdEngineInfoResultDto;
import net.northking.cctp.se.lifecycle.entity.HeartbeatInfoDto;
import net.northking.cctp.se.thread.ExecutorPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 定时计划
 */
@Component
public class LifecycleSchedule
{

  private static final Logger logger = LoggerFactory.getLogger(LifecycleSchedule.class);
  @Autowired
  private EngineRegisterService engineRegisterService;
  @Autowired
  private RabbitTemplate rabbitTemplate;
  @Autowired
  private AtuServerConfig atuServerConfig;
  @Autowired
  private ObjectMapper objectMapper;
  @Autowired
  private DaemonProcess daemonProcess;

  @Value("${atu.server.daemonFlag:true}")
  private boolean daemonFlag;

  /**
   * TODO 登录逻辑
   * 初始延迟时间 2 秒，间隔 30秒
   */
  @Scheduled(initialDelay = 2 * 1000L, fixedDelay = 30 * 1000L)
  public void login()
  {
    EngineRuntime engineRuntime = EngineRuntime.getRuntime();
    ScriptEngineInfo engineInfo = engineRuntime.getEngineInfo();

    if (EngineStatus.INIT.equals(engineInfo.getStatus()) ||
        EngineStatus.LOGIN_FAILED.equals(engineInfo.getStatus()))
    {
      //注册 状态改为注册中
      engineInfo.setStatus(EngineStatus.LOGIN_ING);
      CdEngineInfoResultDto registerInfo = engineRegisterService.register(engineInfo);
      //注册完成，更新引擎信息
      engineInfo.setDeviceId(registerInfo.getDeviceId());
      engineInfo.setEngineId(registerInfo.getEngineId());
      engineInfo.setVersion(atuServerConfig.getEngineVersion());
      engineInfo.setStatus(EngineStatus.LOGIN_SUCCESSFULLY);
    }
  }

  /**
   * 心跳逻辑
   * 初始延迟时间 10 秒，间隔 60秒
   */
  @Scheduled(initialDelay = 10 * 1000L, fixedDelay = 60 * 1000L)
  public void heartbeat()
  {
    EngineRuntime engineRuntime = EngineRuntime.getRuntime();
    ScriptEngineInfo engineInfo = engineRuntime.getEngineInfo();
    if (EngineStatus.LOGIN_SUCCESSFULLY.equals(engineInfo.getStatus()))
    {
      //登录成功后发送心跳
      //心跳信息包括设备id
      logger.debug("引擎状态正常，发送心跳。。。。");
      HeartbeatInfoDto dto = new HeartbeatInfoDto();
      dto.setEngineId(engineInfo.getEngineId());
      dto.setEngineVersion(engineInfo.getVersion());
      // 增加引擎线程池线程使用情况
      Map<String, Object> info = ExecutorPool.info();
      logger.debug("ExecutorPool info:{}",info);
      dto.setExecutePoolInfo(info);
      deployNotice(dto);
    }else{
      logger.info("心跳 引擎信息 未注册 不发送心跳----");
    }
  }

  private void deployNotice(Object object) {
    byte[] json;
    try{
      logger.debug("引擎发送心跳信息到缓存，心跳信息：object:{}", JSONObject.toJSONString(object));
      json = objectMapper.writeValueAsBytes(object);
      MessageBuilder mb = MessageBuilder.withBody(json);
      mb.setContentType(MediaType.APPLICATION_JSON_VALUE);
      rabbitTemplate.send(MQConstant.ENGINE_HEARTBEAT,mb.build());
    }catch (Exception e){
      logger.error("mq消息解析失败:",e);
    }
  }

  /**
   * 守护进程管理
   * 初始延迟时间 10 秒，间隔 60秒
   */
  @Scheduled(fixedDelay = 60 * 1000L)
  public void daemonProcessProtect()
  {
    if(!daemonFlag){
      return;
    }
    if (daemonProcess.isStarted())
    {
      if (!daemonProcess.alive())
      {
        logger.info("【守护进程】进程 PID={} 未响应。", daemonProcess.getPid());
        daemonProcess.shutdown();
        daemonProcess.start();
      }
    } else
    {
      logger.info("【脚本引擎】进程 未启动。尝试启动！");
      daemonProcess.start();
      logger.info("【脚本引擎】进程 启动成功。更新引擎信息！");
      daemonProcess.alive();
    }
  }
}
