/* ============================================================================
 * 서명전에 — TDS AlertDialog 컴포넌트 (Task #161)
 *
 *  · TDS Mobile 2026-03 AlertDialog 스펙. 중요한 정보를 전달하고 단일 확인
 *    버튼으로 닫을 수 있는 다이얼로그. 작업 완료 알림 · 상태 변경 알림 · 피드백.
 *
 *  · 구성:
 *      AlertDialog.Title         — 제목 (기본 <h3> + t4 + bold + grey-800)
 *      AlertDialog.Description   — 설명 (기본 <h3> + t6 + medium + grey-600)
 *      AlertDialog.AlertButton   — 단일 확인 버튼 (기본 medium + blue-500 + bold)
 *
 *  · props (root):
 *      open*                 boolean
 *      title                 React.ReactNode — <AlertDialog.Title> 권장
 *      description           React.ReactNode — 없어도 됨
 *      alertButton           React.ReactNode — <AlertDialog.AlertButton> 권장
 *      closeOnDimmerClick    boolean (기본 true) — false 면 딤 클릭 시 Wiggle
 *      closeOnBackEvent      boolean (기본 true) — 뒤로가기 시 닫힘 (popstate)
 *      onClose               () => void
 *      onEntered             () => void — 등장 애니메이션 완료 후
 *      onExited              () => void — 퇴장 애니메이션 완료 후
 *      portalContainer       HTMLElement (기본 document.body)
 *
 *  · Modal(#137) 과 역할 구분:
 *      자유 레이아웃 다이얼로그 = Modal / 제목+설명+1버튼 표준 = AlertDialog.
 *      ConfirmDialog(#162) 와 구분: 단일 CTA = AlertDialog / 취소+확인 = ConfirmDialog.
 *
 *  · Wiggle: closeOnDimmerClick=false 로 딤 클릭 시 `.tds-alertdialog--wiggle`
 *    클래스를 400ms 부여 → CSS keyframe 좌우 흔들림. 닫히지 않음.
 *
 *  · 모든 색/폰트/간격은 var(--tds-…) 토큰. 하드코딩 없음.
 *  · prefers-reduced-motion 시 모든 transition/애니메이션 OFF (fade 만 120ms).
 *  · aria-modal="true" + role="alertdialog" + aria-labelledby(Title)/aria-describedby(Description) 자동.
 * ========================================================================== */

// ─── Title ───────────────────────────────────────────────────────────
function AlertDialogTitle({
  as = "h3",
  color,
  typography = "t4",
  fontWeight = "bold",
  className = "",
  style,
  children,
  ...rest
}) {
  const Tag = as || "h3";
  const cls = [
    "tds-alertdialog__title",
    "tds-alertdialog__title--" + typography,
    "tds-alertdialog__title--w-" + fontWeight,
    className,
  ]
    .filter(Boolean)
    .join(" ");
  const mergedStyle = Object.assign({}, style || {}, color ? { color: color } : {});
  return (
    <Tag className={cls} style={mergedStyle} {...rest}>
      {children}
    </Tag>
  );
}

// ─── Description ─────────────────────────────────────────────────────
function AlertDialogDescription({
  as = "h3",
  color,
  typography = "t6",
  fontWeight = "medium",
  className = "",
  style,
  children,
  ...rest
}) {
  // 스펙은 as 기본이 "h3" — 시멘틱으로는 어색하지만 스펙 준수. 호출자가 <p> 로 오버라이드 권장.
  const Tag = as || "h3";
  const cls = [
    "tds-alertdialog__description",
    "tds-alertdialog__description--" + typography,
    "tds-alertdialog__description--w-" + fontWeight,
    className,
  ]
    .filter(Boolean)
    .join(" ");
  const mergedStyle = Object.assign({}, style || {}, color ? { color: color } : {});
  return (
    <Tag className={cls} style={mergedStyle} {...rest}>
      {children}
    </Tag>
  );
}

// ─── AlertButton ─────────────────────────────────────────────────────
// TextButton(#153) 위임. 미로드 시 native <button> 폴백.
function AlertDialogAlertButton({
  size = "medium",
  color,
  fontWeight = "bold",
  variant,
  className = "",
  style,
  children,
  onClick,
  ...rest
}) {
  const cls = ["tds-alertdialog__alert-button", className].filter(Boolean).join(" ");

  if (typeof window !== "undefined" && typeof window.TextButton === "function") {
    return React.createElement(
      window.TextButton,
      Object.assign(
        {
          size: size,
          variant: variant,
          className: cls,
          style: style,
          onClick: onClick,
          // TextButton 은 color/fontWeight 를 typography/style 오버라이드 프로퍼티로 받음
          color: color,
          fontWeight: fontWeight,
        },
        rest
      ),
      children
    );
  }

  // 폴백 — TextButton 미로드 환경
  const fallbackCls = [cls, "tds-alertdialog__alert-button--fallback"].filter(Boolean).join(" ");
  const mergedStyle = Object.assign(
    {
      color: color || "var(--tds-blue-500)",
      fontWeight: fontWeight === "regular" ? 400 : fontWeight === "medium" ? 500 : fontWeight === "semibold" ? 600 : 700,
    },
    style || {}
  );
  return (
    <button
      type="button"
      className={fallbackCls}
      style={mergedStyle}
      onClick={onClick}
      {...rest}
    >
      {children}
    </button>
  );
}

// ─── 루트 AlertDialog ───────────────────────────────────────────────
function AlertDialog({
  open,
  title,
  description,
  alertButton,
  closeOnDimmerClick = true,
  closeOnBackEvent = true,
  onClose,
  onEntered,
  onExited,
  portalContainer,
  className = "",
  ...rest
}) {
  const [isMounted, setIsMounted] = React.useState(!!open);
  const [isEntered, setIsEntered] = React.useState(false);
  const [wiggle, setWiggle] = React.useState(0); // 변경할 때마다 애니메이션 재시작
  const exitTimerRef = React.useRef(null);
  const wiggleTimerRef = React.useRef(null);
  const contentRef = React.useRef(null);
  const enteredCalledRef = React.useRef(false);

  // 고유 id — aria-labelledby / aria-describedby 자동 페어링
  const uidRef = React.useRef(null);
  if (uidRef.current == null) {
    uidRef.current = "tds-alertdialog-" + Math.random().toString(36).slice(2, 10);
  }
  const uid = uidRef.current;

  const container =
    portalContainer && typeof portalContainer.appendChild === "function"
      ? portalContainer
      : typeof document !== "undefined"
        ? document.body
        : null;

  // ── open 변화: mount + enter, unmount + exit ──────────────────────
  React.useEffect(function () {
    if (open) {
      if (exitTimerRef.current) {
        window.clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
      setIsMounted(true);
      enteredCalledRef.current = false;
      let raf2 = 0;
      const raf1 = window.requestAnimationFrame(function () {
        raf2 = window.requestAnimationFrame(function () { setIsEntered(true); });
      });
      return function () {
        window.cancelAnimationFrame(raf1);
        if (raf2) window.cancelAnimationFrame(raf2);
      };
    }
    if (!isMounted) return undefined;
    setIsEntered(false);
    if (exitTimerRef.current) window.clearTimeout(exitTimerRef.current);
    exitTimerRef.current = window.setTimeout(function () {
      setIsMounted(false);
      if (typeof onExited === "function") {
        try { onExited(); } catch (_) {}
      }
      exitTimerRef.current = null;
    }, 300);
    return function () {
      if (exitTimerRef.current) {
        window.clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open]);

  // ── body 스크롤 락 ──
  React.useEffect(function () {
    if (!isMounted || typeof document === "undefined") return undefined;
    const root = document.documentElement;
    root.classList.add("tds-alertdialog-open");
    return function () { root.classList.remove("tds-alertdialog-open"); };
  }, [isMounted]);

  // ── ESC ──
  React.useEffect(function () {
    if (!isMounted) return undefined;
    const onKey = function (e) {
      if (e.key === "Escape" || e.key === "Esc") {
        e.stopPropagation();
        if (typeof onClose === "function") onClose();
      }
    };
    document.addEventListener("keydown", onKey);
    return function () { document.removeEventListener("keydown", onKey); };
  }, [isMounted, onClose]);

  // ── popstate (뒤로가기) ──
  React.useEffect(function () {
    if (!isMounted || !closeOnBackEvent) return undefined;
    // 열림 직후 history state 를 하나 push → popstate 시 우리 것을 pop 한 것으로 간주
    const marker = { __tds_alertdialog: uid };
    try { window.history.pushState(marker, ""); } catch (_) {}
    const onPop = function () {
      if (typeof onClose === "function") onClose();
    };
    window.addEventListener("popstate", onPop);
    return function () {
      window.removeEventListener("popstate", onPop);
      // 우리가 push 한 state 가 아직 top 이면 pop — 중복 뒤로가기 방지
      try {
        if (window.history.state && window.history.state.__tds_alertdialog === uid) {
          window.history.back();
        }
      } catch (_) {}
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isMounted, closeOnBackEvent, uid]);

  // ── transitionend → onEntered / onExited ──
  const onTransitionEnd = function (e) {
    if (!e || !e.propertyName) return;
    if (e.target !== contentRef.current) return;
    if (e.propertyName !== "opacity" && e.propertyName !== "transform") return;
    if (isEntered && !enteredCalledRef.current) {
      enteredCalledRef.current = true;
      if (typeof onEntered === "function") {
        try { onEntered(); } catch (_) {}
      }
      return;
    }
    if (!isEntered) {
      if (exitTimerRef.current) {
        window.clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
      setIsMounted(false);
      if (typeof onExited === "function") {
        try { onExited(); } catch (_) {}
      }
    }
  };

  // ── 딤(overlay) 클릭 ──
  const onOverlayClick = function () {
    if (closeOnDimmerClick) {
      if (typeof onClose === "function") onClose();
      return;
    }
    // Wiggle 트리거
    if (wiggleTimerRef.current) window.clearTimeout(wiggleTimerRef.current);
    setWiggle(function (n) { return n + 1; });
    wiggleTimerRef.current = window.setTimeout(function () {
      setWiggle(0);
      wiggleTimerRef.current = null;
    }, 420);
  };

  React.useEffect(function () {
    return function () {
      if (wiggleTimerRef.current) {
        window.clearTimeout(wiggleTimerRef.current);
        wiggleTimerRef.current = null;
      }
    };
  }, []);

  if (!isMounted || !container) return null;

  const rootCls = [
    "tds-alertdialog-portal",
    "tds-alertdialog",
    isEntered && "tds-alertdialog--entered",
    wiggle > 0 && "tds-alertdialog--wiggle",
    className,
  ]
    .filter(Boolean)
    .join(" ");

  // aria-labelledby / aria-describedby: 제공된 경우에만 id 부여
  const titleId = title ? uid + "-title" : undefined;
  const descId = description ? uid + "-desc" : undefined;

  // title / description 에 id 주입 — 이미 id 가 있으면 유지.
  const titleNode = title && React.isValidElement(title)
    ? React.cloneElement(title, Object.assign({}, { id: title.props && title.props.id ? title.props.id : titleId }))
    : title;
  const descNode = description && React.isValidElement(description)
    ? React.cloneElement(description, Object.assign({}, { id: description.props && description.props.id ? description.props.id : descId }))
    : description;

  return ReactDOM.createPortal(
    <div className={rootCls} {...rest}>
      <div
        className="tds-alertdialog__overlay"
        role="button"
        tabIndex={-1}
        aria-label="닫기"
        onClick={onOverlayClick}
      />
      <div
        ref={contentRef}
        className="tds-alertdialog__content"
        role="alertdialog"
        aria-modal="true"
        aria-labelledby={titleId}
        aria-describedby={descId}
        tabIndex={0}
        onTransitionEnd={onTransitionEnd}
        // wiggle key 로 강제 재마운트 없이 animation 재시작
        key={"wiggle-" + wiggle}
      >
        {titleNode ? <div className="tds-alertdialog__title-slot">{titleNode}</div> : null}
        {descNode ? <div className="tds-alertdialog__description-slot">{descNode}</div> : null}
        {alertButton ? <div className="tds-alertdialog__button-slot">{alertButton}</div> : null}
      </div>
    </div>,
    container
  );
}

// 서브 정적 부착
AlertDialog.Title = AlertDialogTitle;
AlertDialog.Description = AlertDialogDescription;
AlertDialog.AlertButton = AlertDialogAlertButton;

window.AlertDialog = AlertDialog;
window.AlertDialogTitle = AlertDialogTitle;
window.AlertDialogDescription = AlertDialogDescription;
window.AlertDialogAlertButton = AlertDialogAlertButton;

Object.assign(window, {
  AlertDialog,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogAlertButton,
});
