// Custom cursor — follows mouse with spring delay, morphs on hover.
// On the first page load (per tab/session), the ring is "born" from the terra
// i-dot inside the frevia wordmark (#frevia-i-dot) and slow-lerps out to the
// real cursor; subsequent navigations/refreshes within the same session use
// the normal fast follow without the birth animation.
const { useEffect, useRef, useState } = React;

function CustomCursor() {
  const ringRef = useRef(null);
  const dotRef = useRef(null);
  const [variant, setVariant] = useState("default"); // default | hover | text
  const [label, setLabel] = useState("");
  const [ringVisible, setRingVisible] = useState(false);
  const [dotVisible, setDotVisible] = useState(false);

  useEffect(() => {
    // First-load detection — only do the i-dot birth on the FIRST load of this session.
    const SESSION_KEY = "frevia.cursorBirthShown";
    let isFirstLoad = false;
    try {
      isFirstLoad = sessionStorage.getItem(SESSION_KEY) !== "1";
      if (isFirstLoad) sessionStorage.setItem(SESSION_KEY, "1");
    } catch (_) {
      isFirstLoad = true;
    }

    // Find origin point: the terra i-dot in the frevia wordmark, if present.
    let originX = window.innerWidth / 2;
    let originY = window.innerHeight / 2;
    const probeOrigin = () => {
      const el = document.getElementById("frevia-i-dot");
      if (el) {
        const r = el.getBoundingClientRect();
        originX = r.left + r.width / 2;
        originY = r.top + r.height / 2;
      }
    };
    probeOrigin();
    const reprobe = setTimeout(probeOrigin, 250);

    // Ring starts at the i-dot ONLY on first load; otherwise wherever the mouse will land.
    let mx = isFirstLoad ? originX : window.innerWidth / 2;
    let my = isFirstLoad ? originY : window.innerHeight / 2;
    let rx = isFirstLoad ? originX : mx;
    let ry = isFirstLoad ? originY : my;
    let dotX = mx, dotY = my;
    let firstRingMove = true;

    // On first load: keep ring hidden until the wordmark color animation finishes (~1800ms),
    // then reveal it AT THE I-DOT and let it slow-lerp to the cursor.
    // On subsequent loads: ring becomes visible on first mousemove with normal speed.
    const RING_READY_DELAY = isFirstLoad ? 1800 : 0;
    const mountedAt = performance.now();
    // Slow lerp during the birth phase, normal lerp after.
    const SLOW_LERP = 0.045;
    const NORMAL_LERP = 0.18;
    const SLOW_DURATION = 1600; // ms after RING_READY_DELAY during which we slow-lerp
    let raf;

    const move = (e) => {
      mx = e.clientX; my = e.clientY;
      dotX = mx; dotY = my;
      setDotVisible(true);
      const elapsed = performance.now() - mountedAt;
      if (elapsed < RING_READY_DELAY) return;
      if (firstRingMove) {
        firstRingMove = false;
        // On first load, snap the ring's render position back to the i-dot
        // before the slow-lerp animation begins. (rx/ry are already at the i-dot
        // for first load; this is just safety.)
        if (isFirstLoad) {
          probeOrigin();
          rx = originX; ry = originY;
        }
        setRingVisible(true);
      }
    };

    let revealedAt = 0;
    const tick = () => {
      // Determine current lerp factor: slow during the birth window, normal afterwards.
      let lerp = NORMAL_LERP;
      if (isFirstLoad && ringVisibleRef.current) {
        if (revealedAt === 0) revealedAt = performance.now();
        const sinceReveal = performance.now() - revealedAt;
        if (sinceReveal < SLOW_DURATION) {
          // ease from slow back up to normal over SLOW_DURATION
          const t = sinceReveal / SLOW_DURATION;
          lerp = SLOW_LERP + (NORMAL_LERP - SLOW_LERP) * t;
        }
      }
      rx += (mx - rx) * lerp;
      ry += (my - ry) * lerp;
      if (ringRef.current) {
        ringRef.current.style.transform = `translate(${rx}px, ${ry}px) translate(-50%, -50%)`;
      }
      if (dotRef.current) {
        dotRef.current.style.transform = `translate(${dotX}px, ${dotY}px) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    const over = (e) => {
      const t = e.target.closest("[data-cursor]");
      if (t) {
        const c = t.getAttribute("data-cursor");
        if (c === "text") {
          setVariant("text");
          setLabel(t.getAttribute("data-cursor-label") || "VIEW");
        } else {
          setVariant("hover");
        }
      } else {
        setVariant("default");
        setLabel("");
      }
    };

    window.addEventListener("mousemove", move);
    window.addEventListener("mouseover", over);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseover", over);
      cancelAnimationFrame(raf);
      clearTimeout(reprobe);
    };
  }, []);

  // Mirror ringVisible into a ref so the rAF loop can read it without re-subscribing.
  const ringVisibleRef = useRef(false);
  useEffect(() => { ringVisibleRef.current = ringVisible; }, [ringVisible]);

  const cls = `cursor cursor--${variant} ${ringVisible ? "is-visible" : "is-hidden"}`;
  return (
    <React.Fragment>
      <div ref={ringRef} className={cls}>
        {variant === "text" ? label : null}
      </div>
      <div ref={dotRef} className={`cursor-dot ${dotVisible ? "is-visible" : "is-hidden"}`} />
    </React.Fragment>
  );
}

window.CustomCursor = CustomCursor;
