import { app, BrowserWindow, session, shell, type BrowserWindowConstructorOptions, type Tray } from 'electron';
import { join } from 'node:path';
import { startDaemon, type DaemonHandle } from './daemon';
import { seedSessionCookie } from './auth';
import { loadWindowState, saveWindowState } from './window-state';
import { createTray } from './tray';
import { initUpdater } from './updater';

const PARTITION = 'persist:arboretum';
const PORT = 7317;

let daemon: DaemonHandle | null = null;
let win: BrowserWindow | null = null;
let tray: Tray | null = null;
let isQuitting = false;
let shuttingDown = false;

// Instance unique : deux instances = deux daemons/ports en conflit.
if (!app.requestSingleInstanceLock()) {
  app.quit();
} else {
  app.on('second-instance', showWindow);
  app.whenReady().then(bootstrap).catch((err: unknown) => {
    console.error('[arboretum-desktop] bootstrap failed:', err);
    app.quit();
  });
}

async function bootstrap(): Promise<void> {
  const dataDir = join(app.getPath('userData'), 'daemon');
  daemon = await startDaemon({ dataDir, port: PORT, onLog: (l) => process.stdout.write(l) });
  await seedSessionCookie(PARTITION, daemon.url, daemon.token);
  createWindow(daemon.url);
  tray = createTray({ show: showWindow, quit: quitApp });
  initUpdater();
}

function showWindow(): void {
  if (!win) return;
  if (win.isMinimized()) win.restore();
  win.show();
  win.focus();
}

function quitApp(): void {
  isQuitting = true;
  app.quit();
}

function createWindow(url: string): void {
  const state = loadWindowState();
  const opts: BrowserWindowConstructorOptions = {
    width: state.width,
    height: state.height,
    backgroundColor: '#09090b',
    webPreferences: {
      partition: PARTITION,
      contextIsolation: true,
      sandbox: true,
      nodeIntegration: false,
      preload: join(__dirname, 'preload.js'),
    },
  };
  if (state.x !== undefined) opts.x = state.x;
  if (state.y !== undefined) opts.y = state.y;

  win = new BrowserWindow(opts);
  if (state.maximized) win.maximize();

  // Liens externes -> navigateur système ; toute navigation hors origine locale est déviée.
  win.webContents.setWindowOpenHandler(({ url: u }) => {
    void shell.openExternal(u);
    return { action: 'deny' };
  });
  win.webContents.on('will-navigate', (e, u) => {
    if (!u.startsWith(url)) {
      e.preventDefault();
      void shell.openExternal(u);
    }
  });

  // Permissions : n'autoriser que les notifications (cohérent avec la Permissions-Policy serveur).
  session.fromPartition(PARTITION).setPermissionRequestHandler((_wc, permission, cb) => cb(permission === 'notifications'));

  const persist = (): void => {
    if (!win) return;
    const b = win.getBounds();
    saveWindowState({ width: b.width, height: b.height, x: b.x, y: b.y, maximized: win.isMaximized() });
  };

  // Fermer la fenêtre = réduire dans le tray (l'app continue en arrière-plan) ; quitter réellement
  // se fait via le menu du tray ou le menu applicatif.
  win.on('close', (e) => {
    persist();
    if (!isQuitting) {
      e.preventDefault();
      win?.hide();
    }
  });
  win.on('closed', () => {
    win = null;
  });

  void win.loadURL(`${url}/`);
}

app.on('before-quit', (e) => {
  // Ne pas quitter avant l'arrêt propre du daemon enfant.
  isQuitting = true;
  if (daemon && !shuttingDown) {
    e.preventDefault();
    void shutdown();
  }
});

async function shutdown(): Promise<void> {
  if (shuttingDown) return;
  shuttingDown = true;
  try {
    await daemon?.stop();
  } finally {
    daemon = null;
    tray?.destroy();
    tray = null;
    app.quit();
  }
}
