import { useEffect } from "react";

/** Tag names whose descendants can receive free-form text input. */
const INPUT_TAGS = new Set(["INPUT", "TEXTAREA", "SELECT"]);

/**
 * Returns true when the keyboard event originated inside a free-form
 * text field, in which case we should NOT consume j/k/escape/`?` —
 * the user is typing, not navigating the table.
 *
 * - `INPUT` / `TEXTAREA` / `SELECT` are the obvious cases.
 * - `contenteditable` elements (e.g. rich text editors) are the
 *   non-obvious one: `target.isContentEditable` is the standard check.
 *
 * Lifted from `useDrawerKeyboard` so both hooks agree on the
 * "is the user typing?" predicate. Keeping it in lock-step matters:
 * if the predicates drift, a future search box might accidentally
 * become a navigation surface in one component but not another.
 */
function isEditableTarget(target: EventTarget | null): boolean {
  if (!(target instanceof HTMLElement)) return false;
  if (INPUT_TAGS.has(target.tagName)) return true;
  return target.isContentEditable;
}

/**
 * Wires keyboard shortcuts for a paginated/filterable table whose rows
 * are keyboard-navigable (j/k to move, ? for help, Esc to close the
 * help overlay). When `enabled` is true, listens for `keydown` on
 * `window` and dispatches:
 *
 *   j / ArrowDown  →  onNext
 *   k / ArrowUp    →  onPrev
 *   Escape         →  onClose
 *   ?              →  onToggleHelp
 *
 * Semantically a sibling of `useDrawerKeyboard`, but tuned for
 * list-row navigation rather than a modal drawer:
 *
 *  - `onNext` / `onPrev` advance/decrement a row index in the
 *    *list* (the caller decides whether to wrap or clamp; this hook
 *    doesn't enforce either policy — it just signals "the user wants
 *    to move").
 *  - `onClose` closes whatever overlay is currently open on the
 *    page — typically just the keyboard-cheatsheet. The hook itself
 *    doesn't own the overlay; it just forwards the key.
 *  - `onToggleHelp` flips the cheatsheet open/closed. The hook does
 *    NOT preempt this on `?` — see KeyboardCheatsheet.tsx for the
 *    matching "skip `?` in the dismiss listener" rule.
 *
 * Keys are ignored when an `<input>`, `<textarea>`, `<select>`, or
 * `contenteditable` element has focus — typing "j" into a search box
 * must not jump rows. `preventDefault` is called for each matched
 * key to suppress the browser's default (arrow keys scrolling the
 * page, Escape closing modals/pausing video, etc.).
 *
 * Recommended pairing: pass `enabled: !helpOpen` so j/k nav yields
 * to the cheatsheet while it's open (the cheatsheet's own dismiss
 * listener still fires for any keypress, including j/k).
 */
export function useRowKeyboard(opts: {
  enabled: boolean;
  onNext: () => void;
  onPrev: () => void;
  onClose: () => void;
  onToggleHelp: () => void;
}): void {
  const { enabled, onNext, onPrev, onClose, onToggleHelp } = opts;

  useEffect(() => {
    if (!enabled) return;

    const handler = (e: KeyboardEvent) => {
      if (isEditableTarget(e.target)) return;

      switch (e.key) {
        case "j":
        case "ArrowDown":
          e.preventDefault();
          onNext();
          break;
        case "k":
        case "ArrowUp":
          e.preventDefault();
          onPrev();
          break;
        case "Escape":
          e.preventDefault();
          onClose();
          break;
        case "?":
          e.preventDefault();
          onToggleHelp();
          break;
      }
    };

    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [enabled, onNext, onPrev, onClose, onToggleHelp]);
}