/**
 * Svelte 5 rune-based keybinding store.
 * Manages global keyboard shortcuts with user-customizable chords.
 * Persists overrides via settings RPC (only non-default bindings saved).
 *
 * Usage:
 *   import { keybindingStore } from './keybinding-store.svelte.ts';
 *   await keybindingStore.init(rpc);
 *
 *   // Register a command handler
 *   keybindingStore.on('palette', () => paletteOpen = true);
 *
 *   // Install the global keydown listener (call once)
 *   keybindingStore.installListener();
 */

// ── Minimal RPC interface ────────────────────────────────────────────────────

interface SettingsRpc {
  request: {
    "keybindings.getAll"(p: Record<string, never>): Promise<{ keybindings: Record<string, string> }>;
    "keybindings.set"(p: { id: string; chord: string }): Promise<{ ok: boolean }>;
    "keybindings.reset"(p: { id: string }): Promise<{ ok: boolean }>;
  };
}

// ── Types ────────────────────────────────────────────────────────────────────

export interface Keybinding {
  id: string;
  label: string;
  category: "Global" | "Navigation" | "Terminal" | "Settings";
  chord: string;
  defaultChord: string;
}

// ── Default bindings ─────────────────────────────────────────────────────────

const DEFAULTS: Keybinding[] = [
  { id: "palette",      label: "Command Palette",      category: "Global",     chord: "Ctrl+K",       defaultChord: "Ctrl+K"       },
  { id: "settings",     label: "Open Settings",         category: "Global",     chord: "Ctrl+,",       defaultChord: "Ctrl+,"       },
  { id: "group1",       label: "Switch to Group 1",     category: "Navigation", chord: "Ctrl+1",       defaultChord: "Ctrl+1"       },
  { id: "group2",       label: "Switch to Group 2",     category: "Navigation", chord: "Ctrl+2",       defaultChord: "Ctrl+2"       },
  { id: "group3",       label: "Switch to Group 3",     category: "Navigation", chord: "Ctrl+3",       defaultChord: "Ctrl+3"       },
  { id: "group4",       label: "Switch to Group 4",     category: "Navigation", chord: "Ctrl+4",       defaultChord: "Ctrl+4"       },
  { id: "newTerminal",  label: "New Terminal Tab",       category: "Terminal",   chord: "Ctrl+Shift+T", defaultChord: "Ctrl+Shift+T" },
  { id: "closeTab",     label: "Close Terminal Tab",     category: "Terminal",   chord: "Ctrl+Shift+W", defaultChord: "Ctrl+Shift+W" },
  { id: "nextTab",      label: "Next Terminal Tab",      category: "Terminal",   chord: "Ctrl+]",       defaultChord: "Ctrl+]"       },
  { id: "prevTab",      label: "Previous Terminal Tab",  category: "Terminal",   chord: "Ctrl+[",       defaultChord: "Ctrl+["       },
  { id: "search",       label: "Global Search",          category: "Global",     chord: "Ctrl+Shift+F", defaultChord: "Ctrl+Shift+F" },
  { id: "notifications",label: "Notification Center",    category: "Global",     chord: "Ctrl+Shift+N", defaultChord: "Ctrl+Shift+N" },
  { id: "minimize",     label: "Minimize Window",        category: "Global",     chord: "Ctrl+M",       defaultChord: "Ctrl+M"       },
  { id: "toggleFiles",  label: "Toggle Files Tab",       category: "Navigation", chord: "Ctrl+Shift+E", defaultChord: "Ctrl+Shift+E" },
  { id: "toggleMemory", label: "Toggle Memory Tab",      category: "Navigation", chord: "Ctrl+Shift+M", defaultChord: "Ctrl+Shift+M" },
  { id: "reload",       label: "Reload App",             category: "Settings",   chord: "Ctrl+R",       defaultChord: "Ctrl+R"       },
];

// ── Chord serialisation helpers ───────────────────────────────────────────────

export function chordFromEvent(e: KeyboardEvent): string {
  const parts: string[] = [];
  if (e.ctrlKey || e.metaKey) parts.push("Ctrl");
  if (e.shiftKey) parts.push("Shift");
  if (e.altKey)   parts.push("Alt");
  const key = e.key === " " ? "Space" : e.key;
  // Exclude pure modifier keys
  if (!["Control", "Shift", "Alt", "Meta"].includes(key)) {
    parts.push(key.length === 1 ? key.toUpperCase() : key);
  }
  return parts.join("+");
}

function matchesChord(e: KeyboardEvent, chord: string): boolean {
  return chordFromEvent(e) === chord;
}

// ── Store ────────────────────────────────────────────────────────────────────

function createKeybindingStore() {
  let bindings = $state<Keybinding[]>(DEFAULTS.map((b) => ({ ...b })));
  let rpc: SettingsRpc | null = null;
  const handlers = new Map<string, () => void>();
  let listenerInstalled = false;

  /** Load persisted overrides and merge with defaults. */
  async function init(rpcInstance: SettingsRpc): Promise<void> {
    rpc = rpcInstance;
    try {
      const { keybindings: overrides } = await rpc.request["keybindings.getAll"]({});
      bindings = DEFAULTS.map((b) => ({
        ...b,
        chord: overrides[b.id] ?? b.defaultChord,
      }));
    } catch (err) {
      console.error("[keybinding-store] Failed to load keybindings:", err);
    }
  }

  /** Set a custom chord for a binding id. Persists to SQLite. */
  function setChord(id: string, chord: string): void {
    bindings = bindings.map((b) => b.id === id ? { ...b, chord } : b);
    rpc?.request["keybindings.set"]({ id, chord }).catch(console.error);
  }

  /** Reset a binding to its default chord. Removes SQLite override. */
  function resetChord(id: string): void {
    const def = DEFAULTS.find((b) => b.id === id);
    if (!def) return;
    bindings = bindings.map((b) => b.id === id ? { ...b, chord: def.defaultChord } : b);
    rpc?.request["keybindings.reset"]({ id }).catch(console.error);
  }

  /** Reset all bindings to defaults. */
  function resetAll(): void {
    for (const b of bindings) {
      if (b.chord !== b.defaultChord) resetChord(b.id);
    }
  }

  /** Register a handler for a binding id. */
  function on(id: string, handler: () => void): void {
    handlers.set(id, handler);
  }

  /** Install a global capture-phase keydown listener. Idempotent. */
  function installListener(): () => void {
    if (listenerInstalled) return () => {};
    listenerInstalled = true;

    function handleKeydown(e: KeyboardEvent): void {
      // Never intercept keys when focus is inside a terminal canvas
      const target = e.target as Element | null;
      if (target?.closest(".terminal-container, .xterm")) return;

      const chord = chordFromEvent(e);
      if (!chord) return;

      for (const b of bindings) {
        if (b.chord === chord) {
          const handler = handlers.get(b.id);
          if (handler) {
            e.preventDefault();
            handler();
            return;
          }
        }
      }
    }

    document.addEventListener("keydown", handleKeydown, { capture: true });
    return () => {
      document.removeEventListener("keydown", handleKeydown, { capture: true });
      listenerInstalled = false;
    };
  }

  return {
    get bindings() { return bindings; },
    init,
    setChord,
    resetChord,
    resetAll,
    on,
    installListener,
  };
}

export const keybindingStore = createKeybindingStore();
