// Global shortcuts — wraps Electron's globalShortcut, tracks registrations
// by an opaque renderer-supplied id so the same accelerator can be
// re-bound without the caller juggling state.
//
// PTT semantics are simulated: Electron's globalShortcut API only delivers
// a "pressed" callback — it has no keyup / release event. We fire
// SHORTCUT_EVT_FIRED on press, then after a 200ms timer fire
// SHORTCUT_EVT_RELEASED. Known limitation; TODO: revisit with
// `uiohook-napi` or `node-global-key-listener` if the press-and-release
// UX is too loose.

import { app, BrowserWindow, globalShortcut, ipcMain } from 'electron';

import {
  CHANNELS,
  type ShortcutEvent,
  type ShortcutKind,
  type ShortcutRegisterArgs,
} from '../ipc-types';

interface Entry {
  accelerator: string;
  kind: ShortcutKind;
}

const registry = new Map<string, Entry>();

export function register(mainWindow: BrowserWindow): void {
  const send = (channel: string, payload: ShortcutEvent): void => {
    if (mainWindow.isDestroyed()) return;
    mainWindow.webContents.send(channel, payload);
  };

  ipcMain.handle(
    CHANNELS.SHORTCUT_REGISTER,
    async (_evt, args: ShortcutRegisterArgs): Promise<boolean> => {
      const { id, accelerator, kind } = args;
      const prev = registry.get(id);
      if (prev) {
        try {
          globalShortcut.unregister(prev.accelerator);
        } catch {
          /* ignore */
        }
        registry.delete(id);
      }
      if (globalShortcut.isRegistered(accelerator)) {
        return false;
      }
      const ok = globalShortcut.register(accelerator, () => {
        const ts = Date.now();
        send(CHANNELS.SHORTCUT_EVT_FIRED, { id, ts });
        if (kind === 'ptt') {
          setTimeout(() => {
            send(CHANNELS.SHORTCUT_EVT_RELEASED, { id, ts: Date.now() });
          }, 200);
        }
      });
      if (!ok) return false;
      registry.set(id, { accelerator, kind });
      return true;
    },
  );

  ipcMain.handle(CHANNELS.SHORTCUT_UNREGISTER, async (_evt, id: string): Promise<void> => {
    const entry = registry.get(id);
    if (!entry) return;
    try {
      globalShortcut.unregister(entry.accelerator);
    } catch {
      /* already gone */
    }
    registry.delete(id);
  });

  ipcMain.handle(CHANNELS.SHORTCUT_IS_REGISTERED, async (_evt, id: string): Promise<boolean> => {
    const entry = registry.get(id);
    if (!entry) return false;
    return globalShortcut.isRegistered(entry.accelerator);
  });

  app.on('will-quit', () => {
    globalShortcut.unregisterAll();
    registry.clear();
  });
}
