import React, { useEffect, useRef, useCallback, useId } from 'react';
import styles from '@/app/styles/components/Modal.module.css';

// Module-level stack of currently-open modal ids, in mount order. Only the
// topmost modal handles keyboard events (Escape / Tab-trap), so closing a
// stacked modal — e.g. a detail modal opened over another modal — doesn't
// also close the one underneath it.
const modalStack: string[] = [];

type ModalSize = 'small' | 'default' | 'wide';

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  size?: ModalSize;
  children: React.ReactNode;
  footer?: React.ReactNode;
}

interface ModalHeaderProps {
  title: string;
  onClose: () => void;
}

interface _ModalBodyProps {
  children: React.ReactNode;
}

// Selector for all focusable elements
const FOCUSABLE_SELECTOR =
  'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';

const Modal: React.FC<ModalProps> = ({
  isOpen,
  onClose,
  title,
  size = 'default',
  children,
  footer,
}) => {
  const modalRef = useRef<HTMLDivElement>(null);
  const previousActiveElement = useRef<HTMLElement | null>(null);
  const modalId = useId();

  // Handle Escape key
  const handleKeyDown = useCallback(
    (e: KeyboardEvent) => {
      // Only the topmost modal in the stack handles keyboard events, so Escape
      // in a stacked modal closes just that modal, not the ones beneath it.
      if (modalStack[modalStack.length - 1] !== modalId) {
        return;
      }
      if (e.key === 'Escape') {
        onClose();
        return;
      }

      // Focus trap: handle Tab key
      if (e.key === 'Tab' && modalRef.current) {
        const focusableElements = modalRef.current.querySelectorAll(FOCUSABLE_SELECTOR);
        const firstElement = focusableElements[0] as HTMLElement;
        const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;

        if (e.shiftKey) {
          // Shift+Tab: if on first element, wrap to last
          if (document.activeElement === firstElement) {
            e.preventDefault();
            lastElement?.focus();
          }
        } else {
          // Tab: if on last element, wrap to first
          if (document.activeElement === lastElement) {
            e.preventDefault();
            firstElement?.focus();
          }
        }
      }
    },
    [onClose, modalId]
  );

  // Maintain the module-level open-modal stack so keyboard events route only to
  // the topmost modal.
  useEffect(() => {
    if (!isOpen) return;
    modalStack.push(modalId);
    return () => {
      const idx = modalStack.lastIndexOf(modalId);
      if (idx !== -1) modalStack.splice(idx, 1);
    };
  }, [isOpen, modalId]);

  // Track if we've already focused on open to avoid re-focusing on callback changes
  const hasFocusedRef = useRef(false);

  // Body overflow and keyboard listener
  useEffect(() => {
    if (isOpen) {
      // Store the currently focused element to restore later (only on first open)
      if (!hasFocusedRef.current) {
        previousActiveElement.current = document.activeElement as HTMLElement;
      }
      document.body.style.overflow = 'hidden';
      document.addEventListener('keydown', handleKeyDown);

      // Focus the first focusable element in the modal (only on first open)
      if (!hasFocusedRef.current) {
        hasFocusedRef.current = true;
        requestAnimationFrame(() => {
          if (modalRef.current) {
            // Check if there's an element with autoFocus attribute
            const autoFocusElement = modalRef.current.querySelector('[autofocus]') as HTMLElement;
            if (autoFocusElement) {
              autoFocusElement.focus();
            } else {
              const firstFocusable = modalRef.current.querySelector(
                FOCUSABLE_SELECTOR
              ) as HTMLElement;
              firstFocusable?.focus();
            }
          }
        });
      }
    } else {
      document.body.style.overflow = 'unset';
      hasFocusedRef.current = false;
    }

    return () => {
      document.body.style.overflow = 'unset';
      document.removeEventListener('keydown', handleKeyDown);

      // Restore focus to the element that was focused before the modal opened
      if (
        !isOpen &&
        previousActiveElement.current &&
        typeof previousActiveElement.current.focus === 'function'
      ) {
        previousActiveElement.current.focus();
      }
    };
  }, [isOpen, handleKeyDown]);

  if (!isOpen) return null;

  const sizeClass = styles[`modal--${size}`] || '';

  return (
    <div className={styles.overlay} onClick={onClose} role="presentation">
      <div
        ref={modalRef}
        className={`${styles.modal} ${sizeClass}`.trim()}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-labelledby="modal-title"
      >
        <ModalHeader title={title} onClose={onClose} />
        {children}
        {footer && <div className={styles.modal__footer}>{footer}</div>}
      </div>
    </div>
  );
};

const ModalHeader: React.FC<ModalHeaderProps> = ({ title, onClose }) => (
  <div className={styles.modal__header}>
    <h2 id="modal-title" className={styles.modal__title}>
      {title}
    </h2>
    <button className={styles.modal__close} onClick={onClose} aria-label="Close modal">
      ×
    </button>
  </div>
);

const ModalBody: React.FC<{ children: React.ReactNode }> = ({ children }) => (
  <div className={styles.modal__body}>{children}</div>
);

export { Modal, ModalHeader, ModalBody };
export default Modal;
