import { app, BrowserWindow, ipcMain, dialog } from 'electron';
import path from 'node:path';
import started from 'electron-squirrel-startup';
import { initDb } from './db';
import { appRouter } from './router';
import { createIPCHandler } from './ipc';
import { getAuthManager } from './auth/auth-manager';
import { getBackendClient } from './api/backend-client';
import { getStore } from './store';
import { startBriefScheduler, stopBriefScheduler } from './ai/orchestrator';
import { startAgentScheduler, stopAgentScheduler } from './agents/agent-scheduler';
import { backfillNoteSummaries } from './db/notes-backfill';
import { runDailyRescan } from './files/daily-rescan';

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (started) {
  app.quit();
}

// ---------------------------------------------------------------------------
// Single-instance lock + deep link (OAuth callback via adiuvai://)
// ---------------------------------------------------------------------------

// In dev, Electron is launched as: `electron . ` (or via electron-forge).
// setAsDefaultProtocolClient on Windows/Linux requires the path to the exe.
if (process.defaultApp) {
  // Dev: electron.exe is the "app" — pass the script path as the second arg
  // so that OS-registered links include it and second-instance receives the URL.
  app.setAsDefaultProtocolClient('adiuvai', process.execPath, [path.resolve(process.argv[1] ?? '.')]);
} else {
  app.setAsDefaultProtocolClient('adiuvai');
}

/**
 * Extract and dispatch an adiuvai:// deep link URL.
 * Delegates to AuthManager so the pending OAuth promise is resolved.
 */
function handleDeepLink(url: string): void {
  if (url.startsWith('adiuvai://oauth/callback')) {
    void getAuthManager().handleOAuthCallback(url);
  }
}

// Windows / Linux: a second instance is launched with the deep link as an argv.
// We prevent the second instance and redirect the URL to the first instance.
const gotSingleInstanceLock = app.requestSingleInstanceLock();
if (!gotSingleInstanceLock) {
  // Another instance already running — hand off and exit.
  app.quit();
} else {
  app.on('second-instance', (_event, argv) => {
    // On Windows the URL is the last argument (e.g. adiuvai://oauth/callback?...)
    const url = argv.find((arg) => arg.startsWith('adiuvai://'));
    if (url) handleDeepLink(url);

    // Bring the existing window to focus.
    const windows = BrowserWindow.getAllWindows();
    if (windows.length > 0) {
      const win = windows[0]!;
      if (win.isMinimized()) win.restore();
      win.focus();
    }
  });
}

// macOS: the OS delivers the URL via this event (no second instance spawned).
app.on('open-url', (event, url) => {
  event.preventDefault();
  handleDeepLink(url);
});

const createWindow = (): BrowserWindow => {
  // Create the browser window.
  const iconPath = path.join(__dirname, '../../assets/logo/logo-icon.png');
  const mainWindow = new BrowserWindow({
    width: 1280,
    height: 800,
    minWidth: 900,
    minHeight: 600,
    titleBarStyle: 'hiddenInset',
    icon: iconPath,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  // and load the index.html of the app.
  if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
    mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
  } else {
    mainWindow.loadFile(
      path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`),
    );
  }

  // Open DevTools in development.
  if (process.env.NODE_ENV === 'development') {
    mainWindow.webContents.openDevTools();
  }

  return mainWindow;
};

// ---------------------------------------------------------------------------
// Dialog IPC — file/folder picker
// ---------------------------------------------------------------------------
ipcMain.handle('dialog:showOpenDialog', (_event, options: Electron.OpenDialogOptions) =>
  dialog.showOpenDialog(options),
);

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
  initDb();
  const win = createWindow();
  createIPCHandler({ router: appRouter, windows: [win] });
  // Persistent device WebSocket for agent triggers — best-effort on startup
  getAuthManager()
    .isAuthenticated()
    .then((authenticated) => {
      if (authenticated) {
        void getBackendClient().connectPersistent();
        // Best-effort notes backfill — runs after WS is likely connected
        setTimeout(() => {
          backfillNoteSummaries().catch((err) =>
            console.error('[NotesBackfill] Startup backfill failed:', err),
          );
        }, 5_000);
      }
    })
    .catch((err) => console.error('[DeviceWS] Startup connect failed:', err));

  startBriefScheduler();
  startAgentScheduler();
  // Delay so WS connection is likely up before triggering rescans
  setTimeout(() => { void runDailyRescan(); }, 10_000);
});

// Clean up the persistent WS and backup timers before the app exits
app.on('will-quit', () => {
  stopBriefScheduler();
  stopAgentScheduler();
  getBackendClient().disconnectPersistent();
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
