import { useEffect, useRef } from 'react';

export type ShortcutHandler = (e: KeyboardEvent) => void;

interface Shortcut {
  /**
   * Match by `e.key` (logical character — layout/language dependent).
   * Use for character shortcuts like `/`, `?`.
   */
  key?: string;
  /**
   * Match by `e.code` (physical key position — layout/language independent).
   * Use for modifier shortcuts like Ctrl+K, Alt+←.
   * `e.code` values: `KeyK`, `KeyS`, `ArrowLeft`, `ArrowRight`, `Escape`, etc.
   */
  code?: string;
  ctrl?: boolean;
  meta?: boolean;
  alt?: boolean;
  shift?: boolean;
  handler: ShortcutHandler;
  /** Don't trigger when typing in inputs/textareas (default: true) */
  ignoreInput?: boolean;
}

const registered: Shortcut[] = [];

function matches(e: KeyboardEvent, s: Shortcut): boolean {
  // check modifiers first
  const modsMatch =
    (s.ctrl || false) === (e.ctrlKey || e.metaKey) &&
    (s.alt || false) === e.altKey &&
    (s.shift || false) === e.shiftKey;
  if (!modsMatch) return false;

  // check key (logical character) or code (physical key position)
  if (s.code) {
    return e.code === s.code;
  }
  if (s.key) {
    return e.key.toLowerCase() === s.key.toLowerCase();
  }
  return false;
}

function isInputFocused(): boolean {
  const el = document.activeElement;
  if (!el) return false;
  const tag = el.tagName;
  return (
    tag === 'INPUT' ||
    tag === 'TEXTAREA' ||
    tag === 'SELECT' ||
    (el as HTMLElement).isContentEditable
  );
}

/**
 * Global keyboard shortcut listener. Registers at capture phase so browser
 * default actions (like Chrome's Ctrl+K omnibox) get intercepted before they
 * fire. Mount once in AppShell.
 */
export function KeyboardListener() {
  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      for (const s of registered) {
        // ignoreInput defaults to true — skip when user is typing
        if ((s.ignoreInput ?? true) && isInputFocused()) continue;

        if (matches(e, s)) {
          e.preventDefault();
          e.stopImmediatePropagation();
          s.handler(e);
          return;
        }
      }
    };

    // Capture phase intercepts before browser defaults (e.g. Chrome Ctrl+K)
    window.addEventListener('keydown', onKeyDown, { capture: true });
    return () => window.removeEventListener('keydown', onKeyDown, { capture: true });
  }, []);

  return null;
}

/**
 * Register a keyboard shortcut. Handles cleanup automatically on unmount.
 * The handler is kept stable via ref so the effect doesn't thrash.
 *
 * Use `.code` for layout-independent shortcuts (Ctrl+K, Alt+←, etc.).
 * Use `.key` for character-based shortcuts (/, ?, etc.).
 */
export function useKeyboard(
  shortcut: Omit<Shortcut, 'handler'> & { handler: ShortcutHandler },
) {
  const handlerRef = useRef<ShortcutHandler>(shortcut.handler);
  handlerRef.current = shortcut.handler;

  useEffect(() => {
    const entry: Shortcut = {
      key: shortcut.key,
      code: shortcut.code,
      ctrl: shortcut.ctrl,
      meta: shortcut.meta,
      alt: shortcut.alt,
      shift: shortcut.shift,
      ignoreInput: shortcut.ignoreInput,
      handler: (e: KeyboardEvent) => handlerRef.current(e),
    };
    registered.push(entry);
    return () => {
      const idx = registered.indexOf(entry);
      if (idx >= 0) registered.splice(idx, 1);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [shortcut.key, shortcut.code, shortcut.ctrl, shortcut.meta, shortcut.alt, shortcut.shift, shortcut.ignoreInput]);
}

/**
 * Check if a keyboard event matches a known Ctrl/Cmd+key pattern.
 */
export function isCtrlCmd(e: KeyboardEvent): boolean {
  return e.ctrlKey || e.metaKey;
}
