/* Custom cursor — magnetic capsule + binary particle emitter + click ripple
   Modes:
     default — dot + outline ring + magnetic snap to [data-cursor], capsule label on hover, 0/1 emitter
     invert  — same, with mix-blend-mode difference
     off     — native cursor
*/
const Cursor = ({ mode = "default" }) => {
  const [isTouch, setIsTouch] = React.useState(
    typeof window !== "undefined" && window.matchMedia &&
    window.matchMedia("(hover: none), (pointer: coarse), (max-width: 720px)").matches
  );
  React.useEffect(() => {
    const mq = window.matchMedia("(hover: none), (pointer: coarse), (max-width: 720px)");
    const update = () => setIsTouch(mq.matches);
    if (mq.addEventListener) mq.addEventListener("change", update);else
    mq.addListener(update);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", update);else
      mq.removeListener(update);
    };
  }, []);

  const dotRef = React.useRef(null);
  const ringRef = React.useRef(null);
  const labelRef = React.useRef(null);
  const ripplesContainerRef = React.useRef(null);
  const particlesContainerRef = React.useRef(null);

  const mousePos = React.useRef({ x: -100, y: -100 });
  const ringPos  = React.useRef({ x: -100, y: -100 });
  const lastEmitPos = React.useRef({ x: -9999, y: -9999 });
  const lastEmitTime = React.useRef(0);

  const [hovering, setHovering] = React.useState(false);
  const [label, setLabel] = React.useState("");
  const [pressed, setPressed] = React.useState(false);
  const hoverEl = React.useRef(null);

  React.useEffect(() => {
    if (mode === "off") return;

    const blendCss = mode === "invert" ? "mix-blend-mode: difference;" : "";

    const spawnParticle = (x, y) => {
      const container = particlesContainerRef.current;
      if (!container) return;
      const p = document.createElement("div");
      const digit = Math.random() < 0.5 ? "0" : "1";

      // If the globe is hovering, let it try to capture the digit:
      // it will spawn extra packet bursts there and ask us to suck the digit
      // INTO the nearest city node instead of letting it drift up and fade.
      let captured = false;
      let target = null;
      if (window.__globeBridge && typeof window.__globeBridge.captureDigit === "function") {
        const res = window.__globeBridge.captureDigit(x, y);
        if (res && res.captured) {
          captured = true;
          target = res; // { captured, screenX, screenY }
        }
      }

      // Small randomized offset around the cursor so the stream feels organic
      const ox = (Math.random() - 0.5) * 18;
      const oy = (Math.random() - 0.5) * 18;
      // Drift behaviour: by default upward sparks; when captured, fly toward the city
      let dx, dy, life;
      if (captured && target) {
        dx = target.screenX - x;
        dy = target.screenY - y;
        life = 520 + Math.random() * 220;
      } else {
        dx = (Math.random() - 0.5) * 24;
        dy = -8 - Math.random() * 18; // slight upward bias, like sparks
        life = 900 + Math.random() * 700; // 0.9 – 1.6 s
      }
      const size = 11 + Math.random() * 6;
      p.textContent = digit;
      p.style.cssText = `
        position: fixed;
        left: ${x + ox}px;
        top: ${y + oy}px;
        font-family: var(--font-mono);
        font-size: ${size}px;
        font-weight: 600;
        line-height: 1;
        color: var(--accent);
        text-shadow: 0 0 6px color-mix(in oklab, var(--accent) 55%, transparent);
        pointer-events: none;
        user-select: none;
        z-index: 9996;
        transform: translate(-50%, -50%);
        will-change: transform, opacity;
        opacity: 0.95;
        transition: transform ${life}ms cubic-bezier(0.22, 1, 0.36, 1), opacity ${life}ms ease-out;
        ${blendCss}
      `;
      container.appendChild(p);
      // Next frame, animate to drifted-faded state
      requestAnimationFrame(() => {
        p.style.transform = `translate(-50%, -50%) translate(${dx}px, ${dy}px)`;
        p.style.opacity = "0";
      });
      setTimeout(() => p.remove(), life + 60);
    };

    let raf;
    const onMove = (e) => {
      mousePos.current.x = e.clientX;
      mousePos.current.y = e.clientY;
      if (dotRef.current) {
        dotRef.current.style.transform =
          `translate3d(${e.clientX}px, ${e.clientY}px, 0) translate(-50%, -50%)`;
      }
      // Distance + time gated emitter — spawns digits along the path
      const dx = e.clientX - lastEmitPos.current.x;
      const dy = e.clientY - lastEmitPos.current.y;
      const dist = Math.hypot(dx, dy);
      const now = performance.now();
      if (dist > 6 && now - lastEmitTime.current > 14) {
        // Spawn a small burst (2-3) per step so the stream feels dense
        const burst = 2 + (Math.random() < 0.4 ? 1 : 0);
        for (let i = 0; i < burst; i++) spawnParticle(e.clientX, e.clientY);
        lastEmitPos.current.x = e.clientX;
        lastEmitPos.current.y = e.clientY;
        lastEmitTime.current = now;
      }
    };

    const onDown = () => setPressed(true);
    const onUp   = (e) => {
      setPressed(false);
      const container = ripplesContainerRef.current;
      if (!container) return;
      const r = document.createElement("div");
      r.style.cssText = `
        position: fixed;
        left: ${e.clientX}px; top: ${e.clientY}px;
        width: 12px; height: 12px;
        margin-left: -6px; margin-top: -6px;
        border: 1px solid var(--accent);
        border-radius: 50%;
        pointer-events: none;
        z-index: 9997;
        animation: cursorRipple 600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
        ${blendCss}
      `;
      container.appendChild(r);
      // Click also bursts a few digits
      for (let i = 0; i < 6; i++) spawnParticle(e.clientX, e.clientY);
      setTimeout(() => r.remove(), 650);
    };

    const tick = () => {
      let tx = mousePos.current.x;
      let ty = mousePos.current.y;
      const el = hoverEl.current;
      if (el) {
        const r = el.getBoundingClientRect();
        const cx = r.left + r.width / 2;
        const cy = r.top + r.height / 2;
        const ddx = mousePos.current.x - cx;
        const ddy = mousePos.current.y - cy;
        tx = mousePos.current.x - ddx * 0.28;
        ty = mousePos.current.y - ddy * 0.28;
      }
      ringPos.current.x += (tx - ringPos.current.x) * 0.22;
      ringPos.current.y += (ty - ringPos.current.y) * 0.22;
      if (ringRef.current) {
        ringRef.current.style.transform =
          `translate3d(${ringPos.current.x}px, ${ringPos.current.y}px, 0) translate(-50%, -50%)`;
      }
      if (labelRef.current) {
        labelRef.current.style.transform =
          `translate3d(${ringPos.current.x}px, ${ringPos.current.y}px, 0) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    const onOver = (e) => {
      const t = e.target.closest("[data-cursor]");
      if (t) {
        hoverEl.current = t;
        setHovering(true);
        setLabel(t.dataset.cursor || "");
      } else {
        hoverEl.current = null;
        setHovering(false);
        setLabel("");
      }
    };

    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseover", onOver);
    window.addEventListener("mousedown", onDown);
    window.addEventListener("mouseup", onUp);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseover", onOver);
      window.removeEventListener("mousedown", onDown);
      window.removeEventListener("mouseup", onUp);
    };
  }, [mode]);

  if (mode === "off" || isTouch) return null;

  const blend = mode === "invert" ? "difference" : "normal";
  const hasLabel = hovering && label;

  return (
    <React.Fragment>
      <style>{`
        @keyframes cursorRipple {
          0%   { width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; opacity: 0.9; }
          100% { width: 90px; height: 90px; margin-left: -45px; margin-top: -45px; opacity: 0; }
        }
      `}</style>

      {/* Particle layer — 0/1 emitted from cursor, stays in place, fades */}
      <div ref={particlesContainerRef} style={{ position: "fixed", inset: 0, pointerEvents: "none", zIndex: 9996 }} />

      {/* Click ripples */}
      <div ref={ripplesContainerRef} style={{ position: "fixed", inset: 0, pointerEvents: "none", zIndex: 9997 }} />

      {/* Center dot */}
      <div
        ref={dotRef}
        style={{
          position: "fixed",
          top: 0, left: 0,
          width: pressed ? 4 : 6,
          height: pressed ? 4 : 6,
          borderRadius: "50%",
          background: "var(--accent)",
          pointerEvents: "none",
          zIndex: 9999,
          mixBlendMode: blend,
          transition: "width 160ms var(--ease-out-quart), height 160ms var(--ease-out-quart), opacity 240ms",
          opacity: hasLabel ? 0 : 1,
        }}
      />

      {/* Magnetic ring */}
      <div
        ref={ringRef}
        style={{
          position: "fixed",
          top: 0, left: 0,
          width: pressed ? 22 : 28,
          height: pressed ? 22 : 28,
          borderRadius: "50%",
          border: `1px solid ${hovering ? "var(--accent)" : "var(--fg)"}`,
          pointerEvents: "none",
          zIndex: 9998,
          transition: "width 280ms var(--ease-out-expo), height 280ms var(--ease-out-expo), border-color 240ms var(--ease-out-quart), opacity 220ms var(--ease-out-quart)",
          mixBlendMode: blend,
          opacity: hasLabel ? 0 : 1,
        }}
      />

      {/* Capsule label on [data-cursor] hover */}
      <div
        ref={labelRef}
        style={{
          position: "fixed",
          top: 0, left: 0,
          padding: "8px 14px",
          borderRadius: 999,
          background: "var(--accent)",
          color: "var(--bg)",
          pointerEvents: "none",
          zIndex: 9998,
          fontFamily: "var(--font-mono)",
          fontSize: 10,
          letterSpacing: "0.1em",
          textTransform: "uppercase",
          whiteSpace: "nowrap",
          mixBlendMode: blend,
          opacity: hasLabel ? 1 : 0,
          transform: "translate3d(-100px,-100px,0) translate(-50%,-50%)",
          transition: "opacity 220ms var(--ease-out-quart)",
          boxShadow: "0 8px 24px -8px rgba(15,15,14,0.4)",
        }}
      >
        {label}
      </div>
    </React.Fragment>
  );
};

window.Cursor = Cursor;
