import { ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'
import path from 'path'
import request from 'request'
import progress from 'request-progress'
// win是所有窗口的引用
import fs from 'fs'
import AdmZip from 'adm-zip'
import logger from '../../utils/util.log'
import appPathUtil from '../../utils/util.apppath'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin'
const isLinux = process.platform === 'linux'

function downloadFile (uri, filePath, onProgress, onSuccess, onError) {
  logger.info('download url', uri)
  progress(request(uri), {
    // throttle: 2000,                    // Throttle the progress event to 2000ms, defaults to 1000ms
    // delay: 1000,                       // Only start to emit after 1000ms delay, defaults to 0ms
    // lengthHeader: 'x-transfer-length'  // Length header to use, defaults to content-length
  })
    .on('progress', function (state) {
      onProgress(state.percent * 100)
      logger.log('progress', state.percent)
    })
    .on('error', function (err) {
      // Do something with err
      logger.error('下载升级包失败', err)
      onError(err)
    })
    .on('end', function () {
      // Do something after request finishes
      onSuccess()
    })
    .pipe(fs.createWriteStream(filePath))
}

// 检测更新，在你想要检查更新的时候执行，renderer事件触发后的操作自行编写
function updateHandle (app, api, win, beforeQuit, quit, log) {
  // // 更新前，删除本地安装包 ↓
  // const updaterCacheDirName = 'dev-sidecar-updater'
  // const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
  // fs.emptyDir(updatePendingPath)
  // // 更新前，删除本地安装包 ↑
  const message = {
    error: '更新失败',
    checking: '检查更新中',
    updateAva: '发现新版本',
    updateNotAva: '当前为最新版本，无需更新'
  }
  // 本地开发环境，改变app-update.yml地址
  if (process.env.NODE_ENV === 'development') {
    // const publishUrl = process.env.VUE_APP_PUBLISH_URL
    // autoUpdater.setFeedURL({
    //   provider: 'generic',
    //   url: publishUrl
    // })
    if (isMac) {
      autoUpdater.updateConfigPath = path.join(__dirname, 'mac/dev-sidecar.app/Contents/Resources/app-update.yml')
    } else if (isLinux) {
      autoUpdater.updateConfigPath = path.join(__dirname, 'linux-unpacked/resources/app-update.yml')
    } else {
      autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
    }
  }

  logger.info('auto updater', autoUpdater.getFeedURL())
  autoUpdater.autoDownload = false

  let partPackagePath = null

  function downloadPart (app, value) {
    const appPath = appPathUtil.getAppRootPath(app)
    const fileDir = path.join(appPath, 'update')
    logger.info('download dir', fileDir)
    try {
      fs.accessSync(fileDir, fs.constants.F_OK)
    } catch (e) {
      fs.mkdirSync(fileDir)
    }
    const filePath = path.join(fileDir, value.version + '.zip')

    downloadFile(value.partPackage, filePath, (data) => {
      win.webContents.send('update', { key: 'progress', value: parseInt(data) })
    }, () => {
      // 文件下载完成
      win.webContents.send('update', { key: 'progress', value: 100 })
      logger.info('升级包下载成功：', filePath)
      partPackagePath = filePath
      win.webContents.send('update', {
        key: 'downloaded',
        value: value
      })
    }, (error) => {
      sendUpdateMessage({ key: 'error', value: error, error: error })
    })
  }

  async function updatePart (app, api, value, partPackagePath, quit) {
    const appPath = appPathUtil.getAppRootPath(app)
    const platform = api.shell.getSystemPlatform()
    let target = path.join(appPath, 'resources')
    if (platform === 'mac') {
      target = path.join(appPath, 'Resources')
    }
    const length = fs.statSync(partPackagePath)
    log.info('安装包大小:', length)

    log.info('开始解压缩，安装升级包', partPackagePath, target)

    try {
      await beforeQuit()
      app.relaunch()
      // 解压缩
      const zip = new AdmZip(partPackagePath)
      zip.extractAllTo(target, true)
      log.info('安装完成，重启app')
    } finally {
      app.exit(0)
    }
  }

  autoUpdater.on('error', function (error) {
    log.info('autoUpdater error', error)
    sendUpdateMessage({ key: 'error', value: error, error: error })
    // dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString())
  })
  autoUpdater.on('checking-for-update', function () {
    log.info('autoUpdater checking-for-update')
    sendUpdateMessage({ key: 'checking', value: message.checking })
  })
  autoUpdater.on('update-available', function (info) {
    log.info('autoUpdater update-available')
    sendUpdateMessage({ key: 'available', value: info })
  })
  autoUpdater.on('update-not-available', function (info) {
    log.info('autoUpdater update-not-available')
    sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva })
  })
  // 更新下载进度
  autoUpdater.on('download-progress', function (progressObj) {
    log.info('autoUpdater download-progress')
    win.webContents.send('update', { key: 'progress', value: parseInt(progressObj.percent) })
  })
  // 更新完成，重启应用
  autoUpdater.on('update-downloaded', function (info) {
    log.info('download complete', info.version)
    win.webContents.send('update', {
      key: 'downloaded',
      value: info
    })
  })

  ipcMain.on('update', (e, arg) => {
    if (arg.key === 'doUpdateNow') {
      if (partPackagePath) {
        updatePart(app, api, arg.value, partPackagePath)
        return
      }
      // some code here to handle event
      beforeQuit().then(() => {
        autoUpdater.quitAndInstall()
        if (app) {
          setTimeout(() => {
            app.exit()
          }, 1000)
        }
      })
    } else if (arg.key === 'checkForUpdate') {
      // 执行自动更新检查
      log.info('autoUpdater checkForUpdates')
      autoUpdater.checkForUpdates()
    } else if (arg.key === 'downloadUpdate') {
      // 下载新版本
      log.info('autoUpdater downloadUpdate')
      autoUpdater.downloadUpdate()
    } else if (arg.key === 'downloadPart') {
      // 下载增量更新版本
      log.info('autoUpdater downloadPart')
      // autoUpdater.downloadUpdate()
      downloadPart(app, arg.value)
    }
  })
  // 通过main进程发送事件给renderer进程，提示更新信息
  function sendUpdateMessage (message) {
    log.info('autoUpdater sendUpdateMessage')
    win.webContents.send('update', message)
  }

  log.info('auto update inited')
  return autoUpdater
}

export default {
  install (context) {
    const { app, api, win, beforeQuit, quit, log } = context
    if (process.env.NODE_ENV === 'development') {
      Object.defineProperty(app, 'isPackaged', {
        get () {
          return true
        }
      })
    }
    updateHandle(app, api, win, beforeQuit, quit, log)
  }
}
