'use client';

import { useCallback, useRef } from 'react';
import { useHotkey } from '@djangocfg/ui-core/hooks';

import type { FlatRow, TreeItemId } from '../types';

export interface UseTreeKeyboardOptions<T> {
  rows: FlatRow<T>[];
  focusedId: TreeItemId | null;
  enabled?: boolean;
  onFocus: (id: TreeItemId) => void;
  onSelect: (id: TreeItemId) => void;
  onActivate: (id: TreeItemId) => void;
  onExpand: (id: TreeItemId) => void;
  onCollapse: (id: TreeItemId) => void;
  onClearSelection: () => void;
}

export interface UseTreeKeyboardReturn {
  /** Attach to the tree container. Hotkeys only fire when focus is inside. */
  ref: (instance: HTMLElement | null) => void;
}

/**
 * Standard tree keyboard navigation, scoped to the container ref.
 *
 *  - ↑ / ↓ : prev / next visible row
 *  - Home / End : first / last visible row
 *  - → : expand folder; if already expanded, jump to first child
 *  - ← : collapse folder; if already collapsed (or leaf), jump to parent
 *  - Enter / Space : activate (folder => toggle, leaf => onActivate)
 *  - Esc : clear selection
 *
 * Built on `useHotkey` (react-hotkeys-hook) — focus gating is automatic; no
 * manual `addEventListener` or `data-scope` juggling.
 */
export function useTreeKeyboard<T>({
  rows,
  focusedId,
  enabled = true,
  onFocus,
  onSelect,
  onActivate,
  onExpand,
  onCollapse,
  onClearSelection,
}: UseTreeKeyboardOptions<T>): UseTreeKeyboardReturn {
  // Keep latest values in refs so the callbacks below stay stable across
  // renders — react-hotkeys-hook re-binds on dep change otherwise.
  const rowsRef = useRef(rows);
  const focusedIdRef = useRef(focusedId);
  rowsRef.current = rows;
  focusedIdRef.current = focusedId;

  const getCurrent = () => {
    const r = rowsRef.current;
    const id = focusedIdRef.current;
    const idx = id ? r.findIndex((x) => x.node.id === id) : -1;
    return { rows: r, idx, current: idx >= 0 ? r[idx] : null };
  };

  const refDown = useHotkey(
    'down',
    () => {
      const { rows: r, idx } = getCurrent();
      if (r.length === 0) return;
      const next = r[Math.min(idx + 1, r.length - 1)] ?? r[0];
      onFocus(next.node.id);
    },
    { enabled, preventDefault: true, description: 'Next row' },
  );

  const refUp = useHotkey(
    'up',
    () => {
      const { rows: r, idx } = getCurrent();
      if (r.length === 0) return;
      const prev = r[Math.max(idx - 1, 0)] ?? r[0];
      onFocus(prev.node.id);
    },
    { enabled, preventDefault: true, description: 'Previous row' },
  );

  const refHome = useHotkey(
    'home',
    () => {
      const { rows: r } = getCurrent();
      if (r.length === 0) return;
      onFocus(r[0].node.id);
    },
    { enabled, preventDefault: true, description: 'First row' },
  );

  const refEnd = useHotkey(
    'end',
    () => {
      const { rows: r } = getCurrent();
      if (r.length === 0) return;
      onFocus(r[r.length - 1].node.id);
    },
    { enabled, preventDefault: true, description: 'Last row' },
  );

  const refRight = useHotkey(
    'right',
    () => {
      const { rows: r, idx, current } = getCurrent();
      if (!current) return;
      if (current.isFolder && !current.isExpanded) {
        onExpand(current.node.id);
      } else if (current.isFolder && current.isExpanded) {
        const next = r[idx + 1];
        if (next) onFocus(next.node.id);
      }
    },
    { enabled, preventDefault: true, description: 'Expand / first child' },
  );

  const refLeft = useHotkey(
    'left',
    () => {
      const { current } = getCurrent();
      if (!current) return;
      if (current.isFolder && current.isExpanded) {
        onCollapse(current.node.id);
      } else if (current.parentId) {
        onFocus(current.parentId);
      }
    },
    { enabled, preventDefault: true, description: 'Collapse / parent' },
  );

  const refActivate = useHotkey(
    ['enter', 'space'],
    () => {
      const { current } = getCurrent();
      if (!current) return;
      onSelect(current.node.id);
      if (current.isFolder) {
        if (current.isExpanded) onCollapse(current.node.id);
        else onExpand(current.node.id);
      } else {
        onActivate(current.node.id);
      }
    },
    { enabled, preventDefault: true, description: 'Activate / toggle' },
  );

  const refEscape = useHotkey(
    'escape',
    () => onClearSelection(),
    { enabled, preventDefault: true, description: 'Clear selection' },
  );

  const ref = useCallback(
    (instance: HTMLElement | null) => {
      refDown(instance);
      refUp(instance);
      refHome(instance);
      refEnd(instance);
      refRight(instance);
      refLeft(instance);
      refActivate(instance);
      refEscape(instance);
    },
    [refDown, refUp, refHome, refEnd, refRight, refLeft, refActivate, refEscape],
  );

  return { ref };
}
