import { app } from 'electron';
import type { AppUpdater } from 'electron-updater';
import { z } from 'zod';

import { logger } from '../logger';
import { isMacOS } from '../utils';
import { updaterSubjects } from './event';

export const ReleaseTypeSchema = z.enum([
  'stable',
  'beta',
  'canary',
  'internal',
]);

export const envBuildType = (process.env.BUILD_TYPE || 'canary')
  .trim()
  .toLowerCase();
export const buildType = ReleaseTypeSchema.parse(envBuildType);
const mode = process.env.NODE_ENV;
const isDev = mode === 'development';

let _autoUpdater: AppUpdater | null = null;

export const quitAndInstall = async () => {
  _autoUpdater?.quitAndInstall();
};

let lastCheckTime = 0;
export const checkForUpdatesAndNotify = async (force = true) => {
  if (!_autoUpdater) {
    return void 0;
  }
  // check every 30 minutes (1800 seconds) at most
  if (force || lastCheckTime + 1000 * 1800 < Date.now()) {
    lastCheckTime = Date.now();
    return await _autoUpdater.checkForUpdatesAndNotify();
  }
  return void 0;
};

export const registerUpdater = async () => {
  // so we wrap it in a function
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const { autoUpdater } = require('electron-updater');

  _autoUpdater = autoUpdater;

  // skip auto update in dev mode
  if (!_autoUpdater || isDev) {
    return;
  }

  // TODO: support auto update on windows and linux
  const allowAutoUpdate = isMacOS();

  _autoUpdater.autoDownload = false;
  _autoUpdater.allowPrerelease = buildType !== 'stable';
  _autoUpdater.autoInstallOnAppQuit = false;
  _autoUpdater.autoRunAppAfterInstall = true;
  _autoUpdater.setFeedURL({
    channel: buildType,
    provider: 'github',
    repo: buildType !== 'internal' ? 'AFFiNE' : 'AFFiNE-Releases',
    owner: 'toeverything',
    releaseType: buildType === 'stable' ? 'release' : 'prerelease',
  });

  // register events for checkForUpdatesAndNotify
  _autoUpdater.on('update-available', info => {
    if (allowAutoUpdate) {
      _autoUpdater?.downloadUpdate().catch(e => {
        logger.error('Failed to download update', e);
      });
      logger.info('Update available, downloading...', info);
    }
    updaterSubjects.updateAvailable.next({
      version: info.version,
      allowAutoUpdate,
    });
  });
  _autoUpdater.on('download-progress', e => {
    logger.info(`Download progress: ${e.percent}`);
    updaterSubjects.downloadProgress.next(e.percent);
  });
  _autoUpdater.on('update-downloaded', e => {
    updaterSubjects.updateReady.next({
      version: e.version,
      allowAutoUpdate,
    });
    // I guess we can skip it?
    // updaterSubjects.clientDownloadProgress.next(100);
    logger.info('Update downloaded, ready to install');
  });
  _autoUpdater.on('error', e => {
    logger.error('Error while updating client', e);
  });
  _autoUpdater.forceDevUpdateConfig = isDev;

  app.on('activate', async () => {
    await checkForUpdatesAndNotify(false);
  });
};
