'use client';

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

interface ModalProps {
  title: string;
  description?: string;
  children?: ReactNode;
  primaryActionLabel?: string;
  secondaryActionLabel?: string;
  onPrimaryAction?: () => void | Promise<void>;
  onSecondaryAction?: () => void;
  onOpenChange?: (open: boolean) => void;
  isOpen: boolean;
}

/**
 * Generic, accessible modal component with backdrop, focus management, and semantic structure.
 * Controlled via the `isOpen` prop; callers handle URL state and routing.
 */
export default function Modal({
  title,
  description,
  children,
  primaryActionLabel,
  secondaryActionLabel,
  onPrimaryAction,
  onSecondaryAction,
  onOpenChange,
  isOpen,
}: ModalProps) {
  const dialogRef = useRef<HTMLDivElement | null>(null);
  const previouslyFocusedElementRef = useRef<Element | null>(null);

  // When the modal opens, remember previous focus and move focus into the dialog
  useEffect(() => {
    if (isOpen) {
      previouslyFocusedElementRef.current = document.activeElement;
      const focusable = getFirstFocusable(dialogRef.current);
      if (focusable) {
        focusable.focus();
      } else if (dialogRef.current) {
        dialogRef.current.focus();
      }
      return;
    }

    // When closing, restore focus
    if (!isOpen && previouslyFocusedElementRef.current instanceof HTMLElement) {
      previouslyFocusedElementRef.current.focus();
    }
  }, [isOpen]);

  // Basic focus trap with keyboard handling (Tab / Shift+Tab, Escape)
  const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {
    if (event.key === 'Escape') {
      if (onOpenChange) {
        onOpenChange(false);
      }
      return;
    }

    if (event.key === 'Tab') {
      const focusable = getFocusableElements(dialogRef.current);
      if (focusable.length === 0) return;

      const first = focusable[0];
      const last = focusable[focusable.length - 1];

      if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      } else if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      }
    }
  };

  const handleBackdropClick = (event: React.MouseEvent<HTMLDivElement>) => {
    if (event.target === event.currentTarget && onOpenChange) {
      onOpenChange(false);
    }
  };

  if (!isOpen) {
    return null;
  }

  return (
    <div
      className="fixed inset-0 z-[60] flex items-center justify-center bg-black/60 px-4"
      role="dialog"
      aria-modal="true"
      aria-labelledby="modal-title"
      aria-describedby={description ? 'modal-description' : undefined}
      onKeyDown={handleKeyDown}
      onClick={handleBackdropClick}
    >
      <div
        ref={dialogRef}
        className="w-full max-w-md rounded-2xl bg-deep-graphite border border-charcoal-outline shadow-2xl outline-none"
        tabIndex={-1}
      >
        <div className="px-6 pt-5 pb-3 border-b border-charcoal-outline/80">
          <h2
            id="modal-title"
            className="text-lg font-semibold text-white"
          >
            {title}
          </h2>
          {description && (
            <p
              id="modal-description"
              className="mt-2 text-sm text-gray-400"
            >
              {description}
            </p>
          )}
        </div>

        <div className="px-6 py-4 text-sm text-gray-100">{children}</div>

        {(primaryActionLabel || secondaryActionLabel) && (
          <div className="flex justify-end gap-3 px-6 py-4 border-t border-charcoal-outline/80">
            {secondaryActionLabel && (
              <button
                type="button"
                onClick={() => {
                  onSecondaryAction?.();
                  onOpenChange?.(false);
                }}
                className="min-h-[40px] rounded-full px-4 py-2 text-sm font-medium text-gray-200 bg-iron-gray border border-charcoal-outline hover:bg-charcoal-outline transition-colors"
              >
                {secondaryActionLabel}
              </button>
            )}
            {primaryActionLabel && (
              <button
                type="button"
                onClick={async () => {
                  if (onPrimaryAction) {
                    await onPrimaryAction();
                  }
                }}
                className="min-h-[40px] rounded-full px-4 py-2 text-sm font-semibold text-white bg-primary-blue shadow-[0_0_15px_rgba(25,140,255,0.4)] hover:shadow-[0_0_25px_rgba(25,140,255,0.6)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-blue transition-all"
              >
                {primaryActionLabel}
              </button>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

function getFocusableElements(root: HTMLElement | null): HTMLElement[] {
  if (!root) return [];
  const selectors = [
    'a[href]',
    'button:not([disabled])',
    'textarea:not([disabled])',
    'input:not([disabled])',
    'select:not([disabled])',
    '[tabindex]:not([tabindex="-1"])',
  ];
  const nodes = Array.from(
    root.querySelectorAll<HTMLElement>(selectors.join(',')),
  );
  return nodes.filter((el) => !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden'));
}

function getFirstFocusable(root: HTMLElement | null): HTMLElement | null {
  const elements = getFocusableElements(root);
  return elements[0] ?? null;
}