import { useEffect, useRef } from 'react';

const FOCUSABLE_SELECTOR = [
  'a[href]',
  'button:not([disabled])',
  'input:not([disabled]):not([type="hidden"])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(', ');

/**
 * Accessibility behavior for custom modal dialogs (we don't use the native
 * <dialog> element, so the browser gives us none of this for free):
 *  - moves focus into the dialog when it opens (unless something inside,
 *    e.g. an autoFocus input, already holds focus)
 *  - restores focus to the previously focused element when it closes
 *  - closes on Escape
 *  - keeps Tab / Shift+Tab cycling inside the dialog
 *
 * Attach the returned ref to the dialog element; it needs tabIndex={-1}.
 * `active` allows conditionally rendered dialogs while keeping the hook
 * call unconditional.
 */
export default function useDialogA11y(active, onClose) {
  const dialogRef = useRef(null);
  // Keep the latest onClose in a ref so the effect below doesn't re-run (and
  // steal focus) when callers pass a fresh inline arrow on every render.
  const onCloseRef = useRef(onClose);
  onCloseRef.current = onClose;

  useEffect(() => {
    if (!active) return;
    const previouslyFocused = document.activeElement;
    const dialog = dialogRef.current;
    if (dialog && !dialog.contains(document.activeElement)) {
      dialog.focus();
    }

    const handleKey = (e) => {
      if (e.key === 'Escape') {
        onCloseRef.current?.();
        return;
      }
      if (e.key !== 'Tab' || !dialogRef.current) return;
      const el = dialogRef.current;
      // Only visible elements — offsetParent is null for display:none subtrees
      const focusable = Array.from(el.querySelectorAll(FOCUSABLE_SELECTOR))
        .filter(node => node.offsetParent !== null);
      if (focusable.length === 0) {
        e.preventDefault();
        el.focus();
        return;
      }
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      const current = document.activeElement;
      if (!el.contains(current)) {
        e.preventDefault();
        (e.shiftKey ? last : first).focus();
      } else if (e.shiftKey && (current === first || current === el)) {
        e.preventDefault();
        last.focus();
      } else if (!e.shiftKey && current === last) {
        e.preventDefault();
        first.focus();
      }
    };
    document.addEventListener('keydown', handleKey);
    return () => {
      document.removeEventListener('keydown', handleKey);
      previouslyFocused?.focus?.();
    };
  }, [active]);

  return dialogRef;
}
