const { useState, useEffect, useRef } = React;

// orbit/SaturnRing.jsx 포털 버전을 paranhalo 사이트 톤(흰 배경 + 파란 로고)으로 리컬러.
// [동작] 1) 원 그리기로 HALO 완성(게이트, 1회)  2) 이후 O 확대/축소는 '스크롤 위치'에 연동(가역).
//   - 스크롤 ↓ : O가 커지며 흩어짐 → 아래 hero 등장
//   - 스크롤 ↑ : O가 다시 작아지며 HALO 로고로 복귀
// 인트로는 #intro-stage(sticky) 안에 그려지고, #intro-zone 높이만큼의 스크롤이 zoom(0~1)을 만든다.
const VB_W = 625.61;
const VB_H = 194.79;
const O_CX = 528.22;
const O_CY = 97.39;
const O_SIZE = 162.79;
const BLUE = "#0B53E0";

const PATHS = {
  H: "M167.04 89.7C160.91 87.13 154.96 85.05 149.18 83.4V28.54H129.34V79.22C75.32 71.93 40.64 101.04 36.18 105.04V28.54H16.34V166.25H36.18V137.27C61.88 100.76 100.66 90.39 129.34 88.24V166.25H149.18V87.91C160.12 88.36 167.04 89.7 167.04 89.7",
  A: "M243.48 49.69L262.03 82.96C237.21 83.99 221.28 93.97 217.37 96.7ZM294.76 102.19L288.56 90.98C302.23 90.49 311.16 92.32 311.16 92.32 301.89 88.49 293.16 86.02 285.02 84.57L281.08 77.44 253.95 28.54H233.1L157.24 165.51 156.83 166.25H178.73L192.41 141.63C215.71 110.55 244.45 98.04 267.82 93.39L308.18 165.99 308.32 166.25H330.23L294.73 102.19Z",
  L: "M357.61 28.54H337.77V166.25H338.27 354.54L357.11 166.15H451.67V146.81H357.61Z",
  Oout: "M527.98 16C485.86 16 451.2 47.9 446.82 88.85 455.18 57.46 483.79 34.33 517.81 34.33 535.7 34.33 552.09 40.73 564.83 51.36 568.34 54.1 571.5 57.27 574.25 60.78 584.88 73.52 591.28 89.91 591.28 107.8 591.28 141.82 568.15 170.43 536.76 178.79 577.71 174.4 609.61 139.75 609.61 97.63 609.61 52.55 573.06 16 527.98 16",
  Oin: "M580.13 119.09C571.12 137.08 552.53 149.44 531.04 149.44 500.73 149.44 476.16 124.88 476.16 94.57 476.16 73.08 488.52 54.49 506.52 45.48 479.77 51.94 459.9 76.01 459.9 104.74 459.9 138.41 487.2 165.71 520.87 165.71 549.6 165.71 573.67 145.83 580.13 119.09",
};

const DRAW_CX = VB_W / 2;
const DRAW_CY = VB_H / 2;
const R = O_SIZE / 2;
const CIRC = 2 * Math.PI * R;
const O_SHIFT = DRAW_CX - O_CX;       // O 제자리 <-> 중앙 수평 이동량
const O_INNER_R = 52;

const clamp01 = (v) => Math.max(0, Math.min(1, v));

function HaloIntro() {
  const [progress, setProgress] = useState(0);
  const [phase, setPhase] = useState(0);          // 0:드래그그리기 1:중앙완성 2:로고완성(포털 트리거)
  const [isClockwise, setIsClockwise] = useState(true);
  const [zoom, setZoom] = useState(0);            // O 확대 진행도 0~1 (포털 애니메이션)
  const [maxScale, setMaxScale] = useState(12);
  const [autoComplete, setAutoComplete] = useState(false);  // 70% 도달 → 나머지 원 자동 완성

  const containerRef = useRef(null);
  const svgRef = useRef(null);
  const isDragging = useRef(false);
  const prevAngle = useRef(null);
  const accumAngle = useRef(0);
  const doneFired = useRef(false);

  // 중앙완성 → 0.8s 머문 뒤 로고완성(스크롤 구동 시작)
  useEffect(() => {
    if (phase === 1) {
      const t = setTimeout(() => setPhase(2), 800);
      return () => clearTimeout(t);
    }
  }, [phase]);

  // 로고 완성 시: intro:done(콘텐츠 reveal 트리거) + 포털을 '트리거 애니메이션'으로 구동.
  // 최상단에서 아래로 1회 → 포털 쭉 재생(0→1) → hero 등장. 위로 1회 → 역재생(1→0) → 로고 복귀.
  // 스크롤 잠금/핀 없음: 재생 중 그 입력만 막고, 통과 후엔 평소처럼 스크롤되어 콘텐츠로 이어짐.
  useEffect(() => {
    if (phase < 2) return;
    document.body.classList.remove("intro-active");
    if (!doneFired.current) {
      doneFired.current = true;
      window.dispatchEvent(new Event("intro:done"));
    }

    let raf = 0;
    let animating = false;
    let open = false;                 // 포털 통과(hero) 상태
    const DUR = 900;                  // 포털 재생 시간(ms)
    const ease = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);
    // 포털 통과 전까지 문서 스크롤 잠금 → 휠/터치가 화면을 움직이지 못하게(들썩임 방지)
    const lockDoc = () => document.body.classList.add("intro-portal-lock");
    const unlockDoc = () => document.body.classList.remove("intro-portal-lock");
    lockDoc();

    const setClasses = (z) => {
      document.body.classList.toggle("hero-in", z >= 0.7);
      document.body.classList.toggle("portal-passed", z >= 0.85);
    };
    const tween = (from, to, done) => {
      animating = true;
      const t0 = performance.now();
      const step = (now) => {
        const t = clamp01((now - t0) / DUR);
        const z = from + (to - from) * ease(t);
        setZoom(z);
        setClasses(z);
        if (t < 1) { raf = requestAnimationFrame(step); }
        else { animating = false; setZoom(to); setClasses(to); if (done) done(); }
      };
      raf = requestAnimationFrame(step);
    };
    const teardown = () => {
      window.removeEventListener("wheel", onWheel);
      window.removeEventListener("touchstart", onTouchStart);
      window.removeEventListener("touchmove", onTouchMove);
      window.removeEventListener("keydown", onKey);
    };
    // 포털은 '한 번만' 통과 — 역재생 없음. 통과 완료 시 잠금 해제 + 리스너 제거 → 완전한 일반 스크롤.
    const openPortal = () => {
      if (animating || open) return;
      open = true;
      tween(0, 1, () => { unlockDoc(); teardown(); });
    };

    const onWheel = (e) => {
      if (open) return;                 // 통과 후: 일반 스크롤(가로채지 않음)
      e.preventDefault();               // 로고 상태: 화면 고정
      if (!animating && e.deltaY > 0) openPortal();
    };
    let touchY = null;
    const onTouchStart = (e) => { touchY = e.touches[0].clientY; };
    const onTouchMove = (e) => {
      if (open || touchY === null) return;
      e.preventDefault();               // 로고 상태: 화면 고정
      const dy = touchY - e.touches[0].clientY;   // +면 아래로 스와이프
      if (!animating && dy > 20) { openPortal(); touchY = null; }
    };
    const onKey = (e) => {
      if (open || animating) return;
      if (e.key === "ArrowDown" || e.key === "PageDown" || e.key === " " || e.key === "Spacebar") {
        e.preventDefault(); openPortal();
      }
    };

    window.addEventListener("wheel", onWheel, { passive: false });
    window.addEventListener("touchstart", onTouchStart, { passive: true });
    window.addEventListener("touchmove", onTouchMove, { passive: false });
    window.addEventListener("keydown", onKey);
    return () => {
      if (raf) cancelAnimationFrame(raf);
      unlockDoc();
      window.removeEventListener("wheel", onWheel);
      window.removeEventListener("touchstart", onTouchStart);
      window.removeEventListener("touchmove", onTouchMove);
      window.removeEventListener("keydown", onKey);
    };
  }, [phase]);

  // 뷰포트에 맞춰 O 최대 확대 배율 계산 (화면을 충분히 덮도록)
  useEffect(() => {
    const compute = () => {
      const rect = svgRef.current && svgRef.current.getBoundingClientRect();
      if (!rect || !rect.width) return;
      const userPerPx = VB_W / rect.width;
      const halfDiag = 0.5 * Math.hypot(window.innerWidth, window.innerHeight);
      const needed = (halfDiag * userPerPx / O_INNER_R) * 1.15;
      setMaxScale(Math.max(8, needed));
    };
    compute();
    // 너비가 바뀔 때(방향 전환)만 재계산 — 카카오 툴바 접힘/펼침(높이만 변화)에는 반응 안 함(잔떨림 방지)
    let lastW = window.innerWidth;
    const onResize = () => { if (window.innerWidth === lastW) return; lastW = window.innerWidth; compute(); };
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // ----- 원 그리기(드래그) — phase 0에서만 -----
  const handlePointerDown = (e) => {
    if (phase !== 0) return;
    isDragging.current = true;
    if (e.target.hasPointerCapture && e.pointerId) e.target.setPointerCapture(e.pointerId);
    const rect = containerRef.current.getBoundingClientRect();
    prevAngle.current = Math.atan2(e.clientY - (rect.top + rect.height / 2), e.clientX - (rect.left + rect.width / 2));
  };
  const handlePointerMove = (e) => {
    if (phase !== 0 || !isDragging.current) return;
    const rect = containerRef.current.getBoundingClientRect();
    const angle = Math.atan2(e.clientY - (rect.top + rect.height / 2), e.clientX - (rect.left + rect.width / 2));
    if (prevAngle.current !== null) {
      let diff = angle - prevAngle.current;
      if (diff > Math.PI) diff -= 2 * Math.PI;
      if (diff < -Math.PI) diff += 2 * Math.PI;
      accumAngle.current += diff;
      setIsClockwise(accumAngle.current >= 0);
      let cur = Math.abs(accumAngle.current) / (2 * Math.PI);
      if (cur >= 0.95) {                      // 95%만 그리면 나머지는 자동 완성 → 다음 단계
        isDragging.current = false;
        setAutoComplete(true);
        setProgress(1);
        setTimeout(() => setPhase(1), 430);   // 자동 완성 모션이 끝난 뒤 전환
        return;
      }
      setProgress(cur);
    }
    prevAngle.current = angle;
  };
  const handlePointerUp = (e) => {
    isDragging.current = false;
    prevAngle.current = null;
    if (e.target.hasPointerCapture && e.pointerId) e.target.releasePointerCapture(e.pointerId);
  };

  const dir = isClockwise ? 1 : -1;
  const a = Math.PI / 2 + progress * 2 * Math.PI * dir;
  const handleX = DRAW_CX + R * Math.cos(a);
  const handleY = DRAW_CY + R * Math.sin(a);

  const drawn = phase > 0;
  const moved = phase >= 2;
  const zooming = moved && zoom > 0;
  // 거대 스케일 + 가우시안 블러는 GPU 부하가 커서 버벅임 → 확대 중엔 필터 제거
  const oFilter = zoom > 0.001 ? "none" : "url(#haloGlow)";

  // O: 제자리 → 중앙 이동 + 확대, 끝에서 흩어짐(dissolve)
  const scale = moved ? Math.pow(maxScale, zoom) : 1;
  const oTranslate = moved ? O_SHIFT * zoom : O_SHIFT;
  const oDissolve = zoom > 0.7 ? clamp01((1 - zoom) / 0.3) : 1;   // 0.7~1 구간에서 페이드아웃(조금 일찍)

  const halHide = clamp01(1 - zoom * 2.2);   // 스크롤 시작하면 HAL 빠르게 사라짐
  const letterStyle = (delay) => ({
    fill: BLUE,
    opacity: moved ? halHide : 0,
    transform: moved ? "translateX(0)" : "translateX(-24px)",
    transition: zooming
      ? "none"
      : `opacity 0.7s ease ${delay}s, transform 0.7s cubic-bezier(0.4,0,0.2,1) ${delay}s`,
  });

  return (
    <div ref={containerRef}
      style={{ position: "relative", width: "min(92vw, 780px)", aspectRatio: `${VB_W} / ${VB_H}`,
               cursor: phase === 0 ? "grab" : "default", touchAction: phase === 0 ? "none" : "auto", userSelect: "none" }}
      onPointerDown={handlePointerDown} onPointerMove={handlePointerMove} onPointerUp={handlePointerUp} onPointerCancel={handlePointerUp}>
      <svg ref={svgRef} width="100%" height="100%" viewBox={`0 0 ${VB_W} ${VB_H}`} style={{ overflow: "visible" }}>
        <defs>
          <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="4" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge>
          </filter>
          <filter id="haloGlow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="5" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge>
          </filter>
        </defs>

        {/* 안내용 점선 가이드 */}
        <circle cx={DRAW_CX} cy={DRAW_CY} r={R} fill="none" stroke="#cdd8ef" strokeWidth="4" strokeDasharray="8 8"
          style={{ opacity: drawn ? 0 : 1, transition: "opacity 0.5s ease" }} />

        {/* 드래그하며 그려지는 진행 원 */}
        <g style={{ transformOrigin: `${DRAW_CX}px ${DRAW_CY}px`, transform: isClockwise ? "rotate(90deg)" : "rotate(90deg) scale(1,-1)" }}>
          <circle cx={DRAW_CX} cy={DRAW_CY} r={R} fill="none" stroke={BLUE} strokeWidth="6" strokeLinecap="round" filter="url(#glow)"
            style={{ strokeDasharray: CIRC, strokeDashoffset: CIRC * (1 - progress), opacity: drawn ? 0 : 1,
              transition: autoComplete
                ? "stroke-dashoffset 0.42s cubic-bezier(0.4,0,0.2,1), opacity 0.6s ease"
                : "opacity 0.6s ease" }} />
        </g>

        {/* 드래그 핸들 점 */}
        <circle cx={handleX} cy={handleY} r="9" fill={BLUE} stroke="#ffffff" strokeWidth="3"
          style={{ opacity: (drawn || autoComplete) ? 0 : 1, transition: "opacity 0.3s ease", filter: "drop-shadow(0 0 6px rgba(11,83,224,0.55))" }} />

        {/* H A L : 완성되면 등장 → 스크롤 시 페이드아웃 */}
        <path d={PATHS.H} style={letterStyle(0.05)} />
        <path d={PATHS.A} style={letterStyle(0.15)} />
        <path d={PATHS.L} style={letterStyle(0.25)} />

        {/* O : 제자리 → 중앙 정렬+확대(스크롤 연동) → 끝에서 흩어짐 */}
        <g style={{
          transformOrigin: `${O_CX}px ${O_CY}px`,
          opacity: drawn ? oDissolve : 0,
          transform: `translateX(${oTranslate}px) scale(${scale})`,
          transition: zooming
            ? "none"
            : "opacity 0.6s ease, transform 0.9s cubic-bezier(0.34,1.3,0.64,1)",
        }}>
          <path d={PATHS.Oout} fill={BLUE} filter={oFilter} />
          <path d={PATHS.Oin} fill={BLUE} filter={oFilter} />
        </g>
      </svg>

      <p style={{ position: "absolute", left: 0, right: 0, bottom: "-64px", textAlign: "center",
        color: "#8a9099", fontSize: "1rem", fontWeight: 600,
        opacity: (phase === 0 && progress === 0) ? 1 : (moved && zoom < 0.04 ? 1 : 0),
        transition: "opacity 0.5s ease", pointerEvents: "none" }}>
        {moved ? "아래로 스크롤하세요" : "점선을 따라 원을 한 바퀴 그려보세요"}
      </p>
    </div>
  );
}

// ===== 개발용 인트로 스킵 스위치 =====
// 콘솔에서  localStorage.skipIntro = "1"  → 인트로 건너뛰고 hero부터 표시(새로고침 유지)
//          delete localStorage.skipIntro  → 다시 인트로 재생
// URL 에 ?nointro 를 붙여도 1회 스킵. (스위치 안 켜면 실제 방문자에겐 평소대로 재생)
const SKIP_INTRO =
  localStorage.getItem("skipIntro") === "1" ||
  location.search.indexOf("nointro") !== -1;

if (SKIP_INTRO) {
  // 인트로를 렌더하지 않고, '통과 완료' 상태로 만들어 hero/콘텐츠를 일반 페이지처럼 표시
  document.body.classList.remove("intro-active");
  document.body.classList.add("intro-skip", "hero-in", "portal-passed");
  // reveal.js 등 intro:done 을 기다리는 스크립트에 완료 신호 전달(안 그러면 .reveal 콘텐츠가 숨은 채 유지)
  window.dispatchEvent(new Event("intro:done"));
} else {
  const introRoot = ReactDOM.createRoot(document.getElementById("intro-svg"));
  introRoot.render(<HaloIntro />);
}
