import { useState, useEffect, useRef, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { cn } from '@/lib/utils';

export interface DropdownProps {
  trigger: React.ReactNode;
  children: React.ReactNode;
  align?: 'left' | 'right' | 'center';
  className?: string;
  /** Controlled open state */
  open?: boolean;
  /** Uncontrolled default open */
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
}

/**
 * Composant Dropdown réutilisable avec menu et gestion du clavier.
 */
export function Dropdown({
  trigger,
  children,
  align = 'left',
  className,
  open: openProp,
  defaultOpen = false,
  onOpenChange,
}: DropdownProps) {
  const [internalOpen, setInternalOpen] = useState(defaultOpen);
  const isControlled = openProp !== undefined;
  const open = isControlled ? openProp : internalOpen;

  const containerRef = useRef<HTMLDivElement>(null);
  const menuRef = useRef<HTMLDivElement>(null);
  const triggerRef = useRef<HTMLDivElement>(null);
  const focusedIndexRef = useRef<number>(-1);

  const handleOpenChange = useCallback(
    (newOpen: boolean) => {
      if (!isControlled) {
        setInternalOpen(newOpen);
      }
      onOpenChange?.(newOpen);
      if (!newOpen) {
        focusedIndexRef.current = -1;
      }
    },
    [onOpenChange, isControlled],
  );

  // Fermer le dropdown quand on clique en dehors
  useEffect(() => {
    if (!open) return;

    const handleClickOutside = (event: MouseEvent) => {
      if (
        containerRef.current &&
        !containerRef.current.contains(event.target as Node)
      ) {
        handleOpenChange(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [open, handleOpenChange]);

  // Gestion du clavier
  useEffect(() => {
    if (!open) return;

    const handleKeyDown = (event: KeyboardEvent) => {
      if (!menuRef.current) return;

      const focusableElements = menuRef.current.querySelectorAll<HTMLElement>(
        'button, [href], input, select, textarea, [role="menuitem"], [tabindex]:not([tabindex="-1"])',
      );

      const elements = Array.from(focusableElements);

      switch (event.key) {
        case 'Escape':
          event.preventDefault();
          handleOpenChange(false);
          triggerRef.current?.focus();
          break;

        case 'ArrowDown':
          event.preventDefault();
          focusedIndexRef.current =
            focusedIndexRef.current < elements.length - 1
              ? focusedIndexRef.current + 1
              : 0;
          elements[focusedIndexRef.current]?.focus();
          break;

        case 'ArrowUp':
          event.preventDefault();
          focusedIndexRef.current =
            focusedIndexRef.current > 0
              ? focusedIndexRef.current - 1
              : elements.length - 1;
          elements[focusedIndexRef.current]?.focus();
          break;

        case 'Enter':
        case ' ':
          event.preventDefault();
          if (
            focusedIndexRef.current >= 0 &&
            elements[focusedIndexRef.current]
          ) {
            elements[focusedIndexRef.current].click();
          }
          break;

        case 'Home':
          event.preventDefault();
          focusedIndexRef.current = 0;
          elements[0]?.focus();
          break;

        case 'End':
          event.preventDefault();
          focusedIndexRef.current = elements.length - 1;
          elements[elements.length - 1]?.focus();
          break;
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [open, handleOpenChange]);

  // Focuser le premier élément quand le menu s'ouvre
  useEffect(() => {
    if (open && menuRef.current) {
      const focusableElements = menuRef.current.querySelectorAll<HTMLElement>(
        'button, [href], input, select, textarea, [role="menuitem"], [tabindex]:not([tabindex="-1"])',
      );
      if (focusableElements.length > 0) {
        focusedIndexRef.current = 0;
        // Petit délai pour s'assurer que le menu est rendu
        setTimeout(() => {
          (focusableElements[0] as HTMLElement)?.focus();
        }, 0);
      }
    }
  }, [open]);

  const alignClasses = {
    left: 'left-0',
    right: 'right-0',
    center: 'left-1/2 -translate-x-1/2',
  };

  return (
    <div ref={containerRef} className={cn('relative', className)}>
      <div
        ref={triggerRef}
        onClick={() => handleOpenChange(!open)}
        role="button"
        aria-haspopup="true"
        aria-expanded={open}
        tabIndex={0}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            handleOpenChange(!open);
          } else if (e.key === 'ArrowDown') {
            e.preventDefault();
            handleOpenChange(true);
          }
        }}
        className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-lg"
        style={{ display: 'inline-block' }}
      >
        {trigger}
      </div>
      {open && (
        <div
          className="fixed inset-0 z-40"
          onClick={() => handleOpenChange(false)}
          aria-hidden="true"
        />
      )}
      <AnimatePresence>
        {open && (
          <motion.div
            key="dropdown-menu"
            ref={menuRef}
            className={cn(
              'absolute z-50 mt-2 min-w-32 bg-card border border-border rounded-xl shadow-lg',
              'overflow-hidden',
              alignClasses[align],
              align === 'right' ? 'origin-top-right' : align === 'center' ? 'origin-top' : 'origin-top-left',
            )}
            role="menu"
            aria-orientation="vertical"
            initial={{ opacity: 0, y: -4 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -4 }}
            transition={{ duration: 0.12, ease: 'easeOut' }}
          >
            {children}
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
