// Auto-updater. Wraps electron-updater; configuration (feed URL) lives in
// package.json's `build.publish`. In dev (`app.isPackaged === false`) we
// short-circuit everything — the feed server is production-only and
// hitting it every launch from a dev machine just adds noise.

import { app, BrowserWindow, ipcMain } from 'electron';
import electronUpdater, {
  type ProgressInfo,
  type UpdateInfo as BuilderUpdateInfo,
} from 'electron-updater';

// electron-updater is a CJS module; named ESM imports don't work. Pull
// autoUpdater off the default export instead.
const { autoUpdater } = electronUpdater;

import {
  CHANNELS,
  type UpdateCheckResult,
  type UpdateInfo,
  type UpdateProgress,
} from '../ipc-types';

let cached: BuilderUpdateInfo | null = null;

function toPublicInfo(info: BuilderUpdateInfo | null): UpdateInfo | null {
  if (!info) return null;
  const notes = info.releaseNotes;
  let releaseNotes: string | null = null;
  if (typeof notes === 'string') releaseNotes = notes;
  else if (Array.isArray(notes)) releaseNotes = notes.map((r) => r.note).join('\n\n');
  return {
    version: info.version ?? '',
    releaseNotes,
  };
}

export function register(mainWindow: BrowserWindow): void {
  autoUpdater.autoDownload = false;
  autoUpdater.autoInstallOnAppQuit = false;

  autoUpdater.on('download-progress', (p: ProgressInfo) => {
    if (mainWindow.isDestroyed()) return;
    const payload: UpdateProgress = {
      percent: p.percent ?? 0,
      transferred: p.transferred ?? 0,
      total: p.total ?? 0,
    };
    mainWindow.webContents.send(CHANNELS.UPDATER_EVT_PROGRESS, payload);
  });

  ipcMain.handle(CHANNELS.UPDATER_CHECK, async (): Promise<UpdateCheckResult> => {
    if (!app.isPackaged) {
      return { available: false, info: null };
    }
    try {
      const result = await autoUpdater.checkForUpdates();
      if (!result || !result.updateInfo) {
        cached = null;
        return { available: false, info: null };
      }
      const current = app.getVersion();
      const remote = result.updateInfo.version;
      if (!remote || remote === current) {
        cached = null;
        return { available: false, info: null };
      }
      cached = result.updateInfo;
      return { available: true, info: toPublicInfo(cached) };
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      if (!/ENOTFOUND|ETIMEDOUT|ECONNRESET|404/i.test(msg)) {
        console.warn('[updater] check failed', err);
      }
      return { available: false, info: null };
    }
  });

  ipcMain.handle(CHANNELS.UPDATER_DOWNLOAD_INSTALL, async (): Promise<void> => {
    if (!app.isPackaged) return;
    if (!cached) throw new Error('no pending update — call check first');
    await autoUpdater.downloadUpdate();
    autoUpdater.quitAndInstall();
  });
}
