import { useEffect, useRef } from 'react';

/**
 * Focus-trap hook for modal-like surfaces (S24).
 *
 * Pass `active` (the modal's open state) and a ref to the container
 * element. While active:
 *
 *   • Focus is moved into the container on mount (first tabbable child,
 *     or the container itself if it has tabindex).
 *   • Tab and Shift+Tab cycle through tabbable descendants only — they
 *     can't escape to elements behind the modal.
 *   • On deactivation (close), focus is returned to wherever it was
 *     before the modal opened.
 *
 * The set of tabbable selectors here covers the common interactive
 * elements; we intentionally exclude `area` and `iframe` since they're
 * unusual in a modal context. `[tabindex="-1"]` is excluded — those are
 * focus targets but not Tab targets.
 *
 * Reading focused elements via `document.activeElement` is the standard
 * pattern; React refs aren't enough because focus may live on an element
 * inside a third-party library (e.g. Filerobot) that doesn't expose its
 * own ref.
 */
const TABBABLE_SELECTOR = [
  'a[href]',
  'button:not([disabled])',
  'input:not([disabled]):not([type="hidden"])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',');

export function useFocusTrap(active, containerRef) {
  const previousFocusRef = useRef(null);

  useEffect(() => {
    if (!active) return undefined;

    // Remember where focus was before so we can restore it on close.
    previousFocusRef.current = document.activeElement;

    const container = containerRef.current;
    if (!container) return undefined;

    // Move focus to the first tabbable element inside the container,
    // falling back to the container itself if it's focusable.
    const focusables = container.querySelectorAll(TABBABLE_SELECTOR);
    const first = focusables[0];
    if (first instanceof HTMLElement) {
      first.focus();
    } else if (container.tabIndex >= 0) {
      container.focus();
    }

    const handleKeyDown = (e) => {
      if (e.key !== 'Tab') return;
      const live = container.querySelectorAll(TABBABLE_SELECTOR);
      if (live.length === 0) {
        // Nothing tabbable — keep focus on the container.
        e.preventDefault();
        if (container.tabIndex >= 0) container.focus();
        return;
      }
      const firstEl = live[0];
      const lastEl = live[live.length - 1];
      const activeEl = document.activeElement;

      if (e.shiftKey && activeEl === firstEl) {
        e.preventDefault();
        lastEl.focus();
      } else if (!e.shiftKey && activeEl === lastEl) {
        e.preventDefault();
        firstEl.focus();
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
      // Restore focus to where it was before, if that element still
      // exists in the DOM. Wrapped in a try/catch because focusing a
      // detached node throws in some browsers.
      const prev = previousFocusRef.current;
      if (prev && typeof prev.focus === 'function') {
        try { prev.focus(); } catch { /* ignore */ }
      }
    };
  }, [active, containerRef]);
}
