import { useCallback, useEffect, useMemo, useRef, useState } from 'react';

/**
 * Arrow keys move focus; Space toggles the focused item in the selection (like
 * ctrl/cmd-click); Enter selects only the focused item (like a plain click).
 */
export function useListKeyboardNav({
  itemIds,
  selectedIds,
  onToggleSelect,
  onSelectSingle,
  enabled = true,
  scrollFallback,
}) {
  const containerRef = useRef(null);
  const itemRefs = useRef(new Map());
  const [focusedId, setFocusedId] = useState(null);

  const indexById = useMemo(() => {
    const map = new Map();
    itemIds.forEach((id, i) => map.set(id, i));
    return map;
  }, [itemIds]);

  useEffect(() => {
    if (itemIds.length === 0) {
      setFocusedId(null);
      return;
    }
    setFocusedId((current) => {
      if (current && indexById.has(current)) return current;
      const firstSelected = itemIds.find((id) => selectedIds.has(id));
      return firstSelected ?? itemIds[0];
    });
  }, [itemIds, selectedIds, indexById]);

  const scrollToId = useCallback(
    (id) => {
      const el = itemRefs.current.get(id);
      if (el) el.scrollIntoView({ block: 'nearest' });
      else scrollFallback?.(indexById.get(id) ?? -1);
    },
    [scrollFallback, indexById]
  );

  const setFocusById = useCallback(
    (id) => {
      if (indexById.has(id)) setFocusedId(id);
    },
    [indexById]
  );

  const registerItemRef = useCallback((id, el) => {
    if (el) itemRefs.current.set(id, el);
    else itemRefs.current.delete(id);
  }, []);

  const moveFocus = useCallback(
    (delta) => {
      if (!focusedId || itemIds.length === 0) return;
      const index = indexById.get(focusedId);
      if (index == null) return;
      const nextIndex = Math.max(0, Math.min(index + delta, itemIds.length - 1));
      const nextId = itemIds[nextIndex];
      setFocusedId(nextId);
      requestAnimationFrame(() => scrollToId(nextId));
    },
    [focusedId, itemIds, indexById, scrollToId]
  );

  const handleKeyDown = useCallback(
    (e) => {
      if (!enabled || itemIds.length === 0) return;

      if (e.key === 'ArrowDown') {
        e.preventDefault();
        moveFocus(1);
        return;
      }

      if (e.key === 'ArrowUp') {
        e.preventDefault();
        moveFocus(-1);
        return;
      }

      if (e.key === ' ' || e.code === 'Space') {
        e.preventDefault();
        if (focusedId) onToggleSelect(focusedId);
        return;
      }

      if (e.key === 'Enter') {
        e.preventDefault();
        if (focusedId) onSelectSingle?.(focusedId);
      }
    },
    [enabled, focusedId, itemIds.length, moveFocus, onToggleSelect, onSelectSingle]
  );

  return {
    containerRef,
    handleKeyDown,
    registerItemRef,
    focusedId,
    setFocusById,
  };
}

export function toggleInSelection(selectedIds, id) {
  const next = new Set(selectedIds);
  if (next.has(id)) next.delete(id);
  else next.add(id);
  return next;
}
