/**
 * 中国蚁剑::更新程序
 * 开写: 2016/05/31
 * 更新: 2016/06/19
 * 说明: 从2.0.0起，取消在线更新程序的方式，改为程序启动一分钟后，检测github->release最新的版本更新信息，然后提示手动更新
 */

const config = require('./config');
const superagent = require('superagent');
const fs = require("fs");
const path = require('path');
const through = require("through");
const tar = require('tar');

class Update {
  constructor(electron) {
    this.logger = new electron.Logger('Update');
    electron
      .ipcMain
      .on('check-update', this.checkUpdate.bind(this))
      .on('check-loader-update', this.checkLoaderUpdate.bind(this))
      .on('update-download', this.onDownlaod.bind(this));
  }

  /**
   * 检查 loader 是否需要更新
   * @param {[type]} event
   */
  checkLoaderUpdate(event) {
    this
      .logger
      .debug('checkLoaderUpdate..')
    superagent
      .get('https://api.github.com/repos/antswordproject/antSword-Loader/releases/latest')
      .end((err, ret) => {
        try {
          let lastInfo = JSON.parse(ret.text);
          let newVersion = lastInfo['tag_name'];
          let curVersion = process.env.AS_LOADER_VER || '2.0.1';
          // 比对版本
          if (this.CompVersion(curVersion, newVersion)) {
            this
              .logger
              .info('Found a new loader version', newVersion);
            event
              .sender
              .send('notification-loader-update', {
                ver: newVersion,
                url: lastInfo['html_url'],
                body: lastInfo['body']
              });
          } else {
            this
              .logger
              .warn('No new loader version.', newVersion, curVersion);
          }
        } catch (e) {
          this
            .logger
            .fatal('ERR', e);
        }
      });
  }

  /**
   * 检查更新
   * 如果有更新，则以通知的方式提示用户手动更新，用户点击跳转到更新页面
   * @return {[type]} [description]
   */
  checkUpdate(event) {
    this
      .logger
      .debug('checkUpdate..');
    superagent
      .get('https://api.github.com/repos/antoor/antSword/releases/latest')
      .end((err, ret) => {
        try {
          let lastInfo = JSON.parse(ret.text);
          let newVersion = lastInfo['tag_name'];
          let curVersion = config['package'].version;
          // 比对版本
          if (this.CompVersion(curVersion, newVersion)) {
            this
              .logger
              .info('Found a new version', newVersion);
            event
              .sender
              .send('notification-update', {
                ver: newVersion,
                url: lastInfo['html_url'],
                body: lastInfo['body']
              });
          } else {
            this
              .logger
              .warn('No new version.', newVersion, curVersion);
          }
        } catch (e) {
          this
            .logger
            .fatal('ERR', e);
        }
      });
  }

  /**
   * 版本比对
   * @param {String} curVer 当前版本
   * @param {String} newVer 新的版本
   * @return {Boolean}
   */
  CompVersion(curVer, newVer) {
    // 如果版本相同
    if (curVer === newVer) {
      return false
    }
    let currVerArr = curVer.split(".");
    let promoteVerArr = newVer.split(".");
    let len = Math.max(currVerArr.length, promoteVerArr.length);
    for (let i = 0; i < len; i++) {
      let proVal = ~~promoteVerArr[i],
        curVal = ~~currVerArr[i];
      if (proVal < curVal) {
        return false;
      } else if (proVal > curVal) {
        return true;
      }
    }
    return false;
  }

  /**
   * 监听下载请求
   * @param  {Object} event ipcMain事件对象
   * @param  {Object} opts  下载配置
   * @return {[type]}       [description]
   */
  onDownlaod(event, opt) {
    const hash = opt['hash'];
    if (!hash) {
      return
    }
    let that = this;

    let savePath = path.join(config.tmpPath, "antsword.tar.gz");

    let tempData = [];
    let totalsize = 0;
    let downsize = 0;
    let url = "https://github.com/AntSwordProject/AntSword/archive/master.tar.gz";
    superagent
      .head(url)
      .set('User-Agent', "antSword/v2.0")
      .redirects(5)
      .timeout(30000)
      .end((err, res) => {
        if (err) {
          event
            .sender
            .send(`update-error-${hash}`, err);
        } else {
          totalsize = parseInt(res.header['content-length']);
          superagent
            .get(url)
            .set('User-Agent', "antSword/v2.0")
            .redirects(5)
            // .proxy(APROXY_CONF['uri']) 设置超时会导致文件过大时写入出错 .timeout(timeout)
            .pipe(through((chunk) => {
              downsize += chunk.length;
              tempData.push(chunk);
              if (totalsize > 0) {
                var progress = parseInt(downsize / totalsize * 100);
                event
                  .sender
                  .send(`update-dlprogress-${hash}`, progress, true);
              } else {
                event
                  .sender
                  .send(`update-dlprogress-${hash}`, downsize, false);
              }
            }, () => {
              that
                .logger
                .debug("Download end.");
              let tempDataBuffer = Buffer.concat(tempData);

              if (totalsize > 0 && downsize != totalsize) {
                event
                  .sender
                  .send(`update-error-${hash}`, "Download Error.");
                return
              }
              event
                .sender
                .send(`update-dlend-${hash}`, tempDataBuffer.length);
              // 同步写入文件
              fs.writeFileSync(savePath, tempDataBuffer);
              // 删除内存数据
              tempDataBuffer = tempData = null;

              // TODO: 需不需要备份?
              // TODO: 删除原来的 node_modules 目录 解压数据
              tar
                .x({
                  file: savePath,
                  strip: 1,
                  C: process.env.AS_WORKDIR
                })
                .then(_ => {
                  that
                    .logger
                    .info("update success.");
                  event
                    .sender
                    .send(`update-success`);
                  fs.unlink(savePath);
                }, err => {
                  event
                    .sender
                    .send(`update-error-${hash}`, err);
                  fs.unlink(savePath);
                });
            }));
        }
      });
  }
}

module.exports = Update;