/**
 * 테마 전환 애니메이션 — View Transitions API + soft circular reveal.
 *
 * 동작: 클릭한 (x, y) 위치에서 새 테마가 부드러운 가장자리(radial-gradient feather)를 가진
 *      원형 mask 로 퍼져나간다. clip-path 와 달리 가장자리가 sharp 하지 않고 색이 자연스럽게
 *      번지는 느낌을 준다.
 *
 * 실제 애니메이션은 globals.css 의 ::view-transition-new(root) 의 mask-image + @property
 * 등록된 --reveal-radius 키프레임이 담당한다. 이 함수는:
 *   1) CSS 커스텀 변수 (--reveal-x/-y/-max) 를 root 에 세팅
 *   2) startViewTransition() 으로 DOM 캡처 → 새 root 의 dark/light 클래스 swap
 *
 * View Transitions API 미지원 브라우저(주로 Firefox)는 즉시 swap 으로 fallback.
 */

type ApplyTheme = (theme: "light" | "dark") => void;

type DocumentWithVT = Document & {
  startViewTransition?: (cb: () => void | Promise<void>) => {
    ready: Promise<void>;
    finished: Promise<void>;
  };
};

export function animatedThemeChange(
  next: "light" | "dark",
  applyTheme: ApplyTheme,
  origin?: { x: number; y: number },
): void {
  const doc = document as DocumentWithVT;

  // 클릭 위치(없으면 화면 중앙)
  const x = origin?.x ?? window.innerWidth / 2;
  const y = origin?.y ?? window.innerHeight / 2;
  // 클릭 지점에서 화면 가장 먼 모서리까지 거리
  const cornerDistance = Math.hypot(
    Math.max(x, window.innerWidth - x),
    Math.max(y, window.innerHeight - y),
  );
  // ★ 중요: 그라데이션의 안쪽 25% 만 solid (alpha 1.0) 이고 나머지 75% 는 페이드.
  // 애니메이션 끝났을 때 화면 모서리가 페이드 구간이 아니라 solid 구간에 들어가야 새 테마가
  // 완전히 화면을 덮은 것처럼 보임. 모서리가 그라데이션의 0.22 (= 1/4.5) 위치에 떨어지도록
  // endRadius 를 모서리 거리의 4.5 배로 설정 → 안쪽 25% 영역 안에 안전하게 들어감.
  const endRadius = cornerDistance * 4.5;

  // CSS 가 사용할 변수 세팅 (root 에 두면 ::view-transition-new(root) 가 상속)
  const root = document.documentElement;
  root.style.setProperty("--reveal-x", `${x}px`);
  root.style.setProperty("--reveal-y", `${y}px`);
  root.style.setProperty("--reveal-max", `${endRadius}px`);
  // Perceived speed 보정: 다크로 갈 땐 검정 컨트라스트가 강해서 같은 duration 도 빠르게 느껴짐.
  // dark 방향만 약 25% 더 길게 잡아 두 방향이 비슷한 속도로 인지되도록 함.
  root.style.setProperty("--vt-duration", next === "dark" ? "2200ms" : "1700ms");

  // View Transitions API 미지원 → 즉시 적용
  if (!doc.startViewTransition) {
    applyTheme(next);
    return;
  }

  // ★ 핵심: VT 캡처 전에 모든 CSS transition 을 일시 비활성화.
  // v5-layout.css 등에서 `transition: all .3s` 같은 규칙이 여러 곳에 깔려있어서, 다크 클래스를
  // 토글하면 background-color / color 가 자체 transition 으로 천천히 보간된다. 그 결과 VT 가
  // 끝난 뒤에도 진짜 DOM 에서 색이 계속 변하는 것처럼 보임("끝났는데 더 어두워지는 느낌").
  // disable style 을 콜백 직전에 주입 → VT 가 새 스냅샷을 캡처할 땐 이미 transition 무효화 →
  // transition.ready 후 제거하면 평소 hover 등은 정상 동작.
  const disableStyle = document.createElement("style");
  disableStyle.setAttribute("data-vt-theme-disable", "");
  // ★ transition 만 죽이고 animation 은 그대로 둘 것!
  // animation-duration:0s 를 넣으면 VT 의 vt-soft-reveal 애니메이션이 영향을 받아
  // 퍼지는 속도가 빨라진다. 우리가 막고 싶은 건 색깔 보간(transition)만이지 animation 이 아님.
  disableStyle.appendChild(
    document.createTextNode(
      "*,*::before,*::after{transition:none!important;}",
    ),
  );

  const transition = doc.startViewTransition(() => {
    // disable 주입 → 클래스 토글이 transition 없이 즉시 반영되도록
    document.head.appendChild(disableStyle);
    // VT 의 캡처 시점에 DOM 이 새 테마 상태가 되도록 즉시 클래스 토글.
    // next-themes 도 함께 호출해서 localStorage / context 동기화.
    document.documentElement.classList.toggle("dark", next === "dark");
    applyTheme(next);
  });

  // 새 스냅샷 캡처 완료 후 disable 제거 — 이 시점엔 진짜 DOM 은 VT pseudo 뒤에 가려져 있어
  // 사용자 눈에는 안 보이지만, transition 은 평소대로 복구되어 hover 등에 영향 없음
  transition.ready
    .then(() => {
      // 강제 reflow 후 제거 (브라우저가 disable 상태를 확실히 적용한 뒤 풀도록)
      void document.body.offsetHeight;
      disableStyle.remove();
    })
    .catch(() => {
      // VT 실패 시에도 disable 은 제거해야 함
      disableStyle.remove();
    });
}
