/*
 * 공용 Modal(중앙 다이얼로그) — Nifty 모달 패턴(docs/DESIGN_SYSTEM_NIFTY.md §2.6):
 * 백드롭(반투명·클릭 닫기) + 카드(radius-lg) + 헤더(제목·닫기 X) / 바디 / 푸터(액션 우측).
 *
 * 특징(Offcanvas 컨벤션과 동일)
 *  - Esc 닫기 · 포커스 트랩(Tab 순환) · 열림 시 패널 포커스, 닫힘 시 이전 포커스 복원
 *  - 열려있는 동안 body 스크롤 잠금 · 페이드/스케일 트랜지션(reduced-motion 존중)
 *  - role=dialog · aria-modal · aria-label(title) · kx 토큰 기반 다크 대응
 *
 * 사용:
 *   <Modal open={open} onClose={close} title="평면도" size="xl" footer={<Button…/>}>…</Modal>
 */
import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react';
import { IconClose } from './icons';
import './modal.css';

export type ModalSize = 'sm' | 'md' | 'lg' | 'xl';

export interface ModalProps {
  open: boolean;
  onClose: () => void;
  title: string;
  /** 패널 폭 규격. 기본 'md'(560). xl 은 평면도 등 대형 뷰어. */
  size?: ModalSize;
  children: ReactNode;
  /** 제목 옆 부가 액션 슬롯(선택). */
  headerExtra?: ReactNode;
  /** 하단 고정 푸터(액션 버튼, 선택). */
  footer?: ReactNode;
  /** 바디 여백 제거(이미지·캔버스 전면 표시용). */
  flushBody?: boolean;
}

const EXIT_MS = 200;

export function Modal({ open, onClose, title, size = 'md', children, headerExtra, footer, flushBody }: ModalProps) {
  const [mounted, setMounted] = useState(open);
  const [visible, setVisible] = useState(false);
  const panelRef = useRef<HTMLDivElement>(null);
  const prevFocusRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (open) {
      prevFocusRef.current = document.activeElement as HTMLElement | null;
      setMounted(true);
      const id = requestAnimationFrame(() => setVisible(true));
      return () => cancelAnimationFrame(id);
    }
    setVisible(false);
    const timer = window.setTimeout(() => setMounted(false), EXIT_MS);
    return () => window.clearTimeout(timer);
  }, [open]);

  useEffect(() => {
    if (visible) {
      panelRef.current?.focus();
    } else if (prevFocusRef.current) {
      prevFocusRef.current.focus?.();
    }
  }, [visible]);

  useEffect(() => {
    if (!mounted) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      document.body.style.overflow = prev;
    };
  }, [mounted]);

  const onKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLDivElement>) => {
      if (e.key === 'Escape') {
        e.stopPropagation();
        onClose();
        return;
      }
      if (e.key !== 'Tab') return;
      const panel = panelRef.current;
      if (!panel) return;
      const focusables = panel.querySelectorAll<HTMLElement>(
        'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])',
      );
      if (focusables.length === 0) {
        e.preventDefault();
        panel.focus();
        return;
      }
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      const active = document.activeElement;
      if (e.shiftKey) {
        if (active === first || active === panel) {
          e.preventDefault();
          last.focus();
        }
      } else if (active === last) {
        e.preventDefault();
        first.focus();
      }
    },
    [onClose],
  );

  if (!mounted) return null;

  return (
    <div className={`kx-modal2${visible ? ' is-open' : ''}`}>
      <div className="kx-modal2__backdrop" onClick={onClose} aria-hidden="true" />
      <div
        ref={panelRef}
        className={`kx-modal2__panel kx-modal2__panel--${size}`}
        role="dialog"
        aria-modal="true"
        aria-label={title}
        tabIndex={-1}
        onKeyDown={onKeyDown}
      >
        <header className="kx-modal2__head">
          <h2 className="kx-modal2__title">{title}</h2>
          {headerExtra && <div className="kx-modal2__headextra">{headerExtra}</div>}
          <button type="button" className="kx-modal2__close" aria-label={`${title} 닫기`} onClick={onClose}>
            <IconClose size={20} />
          </button>
        </header>
        <div className={`kx-modal2__body${flushBody ? ' is-flush' : ''}`}>{children}</div>
        {footer && <footer className="kx-modal2__foot">{footer}</footer>}
      </div>
    </div>
  );
}
