import { useEffect, useRef, type ReactNode } from 'react';

/**
 * FocusTrapProps - Propriétés du composant FocusTrap
 *
 * @interface FocusTrapProps
 */
interface FocusTrapProps {
  /**
   * Contenu à encapsuler dans le piège de focus
   */
  children: ReactNode;

  /**
   * Si `true`, active le piège de focus
   *
   * @default true
   */
  active?: boolean;

  /**
   * Fonction appelée lorsque la touche Escape est pressée
   *
   * @example
   * ```tsx
   * <FocusTrap onEscape={() => setOpen(false)}>
   *   <Dialog />
   * </FocusTrap>
   * ```
   */
  onEscape?: () => void;
}

/**
 * FocusTrap - Composant pour piéger le focus dans une zone
 *
 * Composant qui piège le focus à l'intérieur d'une zone spécifique,
 * utile pour les modales et les dialogues. Le focus reste dans la zone
 * et revient au début lorsqu'on atteint la fin avec Tab.
 *
 * @example
 * ```tsx
 * // Piège de focus pour une modale
 * <FocusTrap active={isOpen} onEscape={() => setIsOpen(false)}>
 *   <div className="modal">
 *     <button>Premier bouton</button>
 *     <button>Deuxième bouton</button>
 *     <button>Dernier bouton</button>
 *   </div>
 * </FocusTrap>
 * ```
 *
 * @component
 * @param {FocusTrapProps} props - Propriétés du composant
 * @returns {JSX.Element} Div avec tabIndex={-1} contenant les enfants
 */

export function FocusTrap({
  children,
  active = true,
  onEscape,
}: FocusTrapProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const previousActiveElement = useRef<Element | null>(null);

  useEffect(() => {
    if (!active || !containerRef.current) return;

    // Sauvegarder l'élément actuellement actif
    previousActiveElement.current = document.activeElement;

    // Trouver tous les éléments focusables
    const focusableElements = containerRef.current.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
    );

    const firstElement = focusableElements[0] as HTMLElement;
    const lastElement = focusableElements[
      focusableElements.length - 1
    ] as HTMLElement;

    // Focuser le premier élément
    if (firstElement) {
      firstElement.focus();
    }

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        onEscape?.();
        return;
      }

      if (event.key === 'Tab') {
        if (event.shiftKey) {
          // Shift + Tab
          if (document.activeElement === firstElement) {
            event.preventDefault();
            lastElement?.focus();
          }
        } else {
          // Tab
          if (document.activeElement === lastElement) {
            event.preventDefault();
            firstElement?.focus();
          }
        }
      }
    };

    document.addEventListener('keydown', handleKeyDown);

    return () => {
      document.removeEventListener('keydown', handleKeyDown);
      // Restaurer le focus à l'élément précédent
      if (previousActiveElement.current instanceof HTMLElement) {
        previousActiveElement.current.focus();
      }
    };
  }, [active, onEscape]);

  return (
    <div ref={containerRef} tabIndex={-1}>
      {children}
    </div>
  );
}
