package net.northking.cctp.daemon.schedule;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.northking.cctp.daemon.config.DaemonProperties;
import net.northking.cctp.daemon.entity.ScriptEngineVersion;
import net.northking.cctp.daemon.service.DaemonService;
import net.northking.cctp.daemon.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 定时检查版本并下载最新的版本
 */
@Component
public class UpgradeSchedule
{
  private static final Logger logger = LoggerFactory.getLogger(UpgradeSchedule.class);

  /**
   * 初始延迟时间 5 秒，单位：毫秒。（系统启动后开始算，第一次执行的时间延迟 N 毫秒）
   */
  private static final long INITIAL_DELAY = 10 * 1000L;

  /**
   * 上一次执行结束时间点之后 60秒再执行
   */
  public static final long FIXED_DELAY = 2*60 * 1000L;

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private final DaemonProperties properties;

  private final RestTemplate restTemplate;

  private final DaemonService daemonService;

  public UpgradeSchedule(DaemonProperties properties, RestTemplate restTemplate, DaemonService daemonService)
  {
    this.properties = properties;
    this.restTemplate = restTemplate;
    this.daemonService = daemonService;
  }


  /**
   * 校验设备管理引擎版本是否更新
   * 如果更新则下载引擎包
   */
  @Scheduled(initialDelay = INITIAL_DELAY,fixedDelay = FIXED_DELAY)
  public void upgrade()
  {
    logger.info("常规检查 ------------ 引擎版本更新检查");
    loadLastVersion();
    downloadLastVersion();
    unZipAppPatch();
    upgradeEngine();
  }




  private void loadLastVersion()
  {
    if (daemonService.preparedLoadLastVersion())
    {
      String centerUrl = properties.getCenterUrl();
      String url = centerUrl + "/api/cctp-device-mgr/pub/engine/release/latest";
      Map<String, String> uriVariables = new HashMap<>();

      String responseBody = restTemplate.getForObject(url, String.class, uriVariables);
      logger.debug("最新版本信息，请求接口：HTTP GET {}", url);
      logger.debug("收到最新版本信息报文：{}", responseBody);
      try
      {
        ScriptEngineVersion lastVersion = objectMapper.readValue(responseBody,
            new TypeReference<ScriptEngineVersion>()
            {
            });
        if(lastVersion==null || StringUtils.isEmpty(lastVersion.getVersion())){
          return;
        }
        daemonService.updateLastVersion(lastVersion);
      } catch (JsonProcessingException e)
      {
        logger.error("获取最新版本信息失败！", e);
      }
    }
    if(daemonService.getInfo()==null){
      String jarFile = properties.getEngineHome() + "/" + properties.getEngine().getJarFile();
      if (!new File(jarFile).exists()){
        logger.info("触发初始完整版本下载-------");
        ScriptEngineVersion initVersion = new ScriptEngineVersion();
        initVersion.setVersion("1.0.0");
        initVersion.setDownloadUrl(properties.getInitFile());
        daemonService.updateInitVersion(initVersion);
      }
    }
  }

  private void downloadLastVersion()
  {
    if (daemonService.preparedDownload())
    {
      String downloadUrl = daemonService.getDownloadUrl();
      downloadUrl = properties.getCenterUrl() +"/api/cctp-files/pub/download/"+ downloadUrl;
      File downloadHome = new File(properties.getDownloadHome());
      downloadHome.mkdirs();

      if (downloadUrl.length() > 0)
      {
        logger.debug("下载安装补丁，请求接口：{}", downloadUrl);
        File patchFile = restTemplate.execute(downloadUrl, HttpMethod.GET, null, response ->
        {
          ContentDisposition disposition = response.getHeaders().getContentDisposition();
          String fileName = disposition.getFilename();
          File file = new File(downloadHome, fileName);
          StreamUtils.copy(response.getBody(), new FileOutputStream(file));
          return file;
        });
        daemonService.downloadCompleted(patchFile);
      }
    }
  }

  private void unZipAppPatch()
  {
    if (daemonService.preparedUnZip())
    {
      File patchFile = new File(daemonService.getUnZipFile());
      String fileName = patchFile.getName().replace(".zip", "");
      File patchHome = new File(properties.getPatchHome());
      File patchDir = new File(patchHome, fileName);

      if (patchFile.length() > 0)
      {
        try
        {
          FileUtils.unZip(patchFile, patchDir);
          daemonService.unZipCompleted(patchDir.getAbsolutePath());
          logger.info("解压缩ZIP包： ZIP文件={}，解压缩到目录={}", patchFile.getAbsolutePath(), patchDir.getAbsolutePath());
        } catch (IOException e)
        {
          logger.error("解压缩安装程序失败！", e);
        }
      }
    }
  }

  private void upgradeEngine()
  {
    if (daemonService.preparedUpgradeEngine())
    {
      File patchDir = new File(daemonService.getPatchDirectory());
      File engineHome = new File(properties.getEngineHome());
      if (patchDir.exists() && patchDir.isDirectory())
      {
        try
        {
          logger.info("升级脚本引擎： 补丁目录={} ， 目标目录={}", patchDir, engineHome);
          if(!engineHome.exists()){
            engineHome.mkdirs();
          }
          FileUtils.copyFolder(patchDir, engineHome);
          writeNameToFile();
          daemonService.upgradeCompleted();
        } catch (IOException e)
        {
          logger.error("更新引擎失败！", e);
        }
      }
    }
  }
  /**
   * 写出当前版本的jar名称文件
   */
  private void writeNameToFile(){
    String path = properties.getEngineHome()+ "/" + properties.getEngine().getJarFile();
    File nameFile = new File(path );
    FileWriter fw = null;
    try {
      fw = new FileWriter(nameFile);
      String name = "atu-script-engine.jar";
      fw.write(name);
      fw.flush();
      logger.info("引擎更新文件成功  引擎新版本为:{}",name);
    } catch (IOException e) {
      logger.error("更新引擎启动文件失败！", e);
    } finally {
      if (fw != null){
        try {
          fw.close();
        } catch (IOException e) {
          logger.error("关闭流异常:", e);
        }
      }
    }
  }

  /**
   * 生成文件
   */
  private void genStartBatFile() {
    String path = properties.getEngineHome();
    String filename = "atu-script-engine-"+daemonService.getInfo().getUpgradeVersion()+".jar";
    StringBuilder commandStr = new StringBuilder();
    commandStr.append("java -jar");
    commandStr.append(" -Xms").append(properties.getEngine().getOpsXms());
    commandStr.append(" -Xmx").append(properties.getEngine().getOpsXmx());
    commandStr.append(" -XX:PermSize=").append(properties.getEngine().getOpsPermSize());
    commandStr.append(" -Dloader.path=.,lib,modules");
    commandStr.append(" -Dfile.encoding=").append(properties.getEngine().getEncoding());
    commandStr.append(" -Dspring.config.location=config/application.yml");
    commandStr.append(" ").append(filename);

    String extParams = properties.getEngine().getExtParams();
    if (extParams != null)
    {
      commandStr.append(" ").append(extParams);
    }
    File nameFile = new File(path+"/start.bat");
    if(nameFile.exists()){
      boolean delete = nameFile.delete();
      logger.info("删除nameFile：{}",delete);
    }
    FileWriter fw = null;
    try {
      fw = new FileWriter(nameFile);
      fw.write("@echo off\r\n");
      fw.write("chcp 65001\r\n");
      fw.write("title=执行引擎\r\n");
      fw.write(commandStr.toString()+"\r\n");
      fw.write("@pause");
      fw.flush();
      logger.info("创建新的启动文件成功");
    } catch (IOException e) {
      logger.error("创建新的启动文件失败！", e);
    }finally {
      try {
        if (fw!=null) {
          fw.close();
        }
      } catch (IOException e) {
        logger.error("关闭流异常:", e);
      }
    }
  }
}
