/* ============= custom cursor, scramble, magnetic, reveal ============== */

/* --- Custom cursor with smoothed follow + mode --- */
function useCursor(showNative) {
  const ringRef = React.useRef(null);
  const dotRef = React.useRef(null);
  const target = React.useRef({ x: window.innerWidth/2, y: window.innerHeight/2 });
  const pos = React.useRef({ x: window.innerWidth/2, y: window.innerHeight/2 });
  const [mode, setMode] = React.useState(""); // is-link / is-view / is-text / is-drag

  React.useEffect(() => {
    document.body.classList.toggle("show-native-cursor", showNative);
    if (showNative) {
      if (ringRef.current) ringRef.current.style.display = "none";
      if (dotRef.current) dotRef.current.style.display = "none";
    } else {
      if (ringRef.current) ringRef.current.style.display = "";
      if (dotRef.current) dotRef.current.style.display = "";
    }
  }, [showNative]);

  React.useEffect(() => {
    const onMove = (e) => { target.current.x = e.clientX; target.current.y = e.clientY; };
    window.addEventListener("pointermove", onMove);

    let raf;
    const tick = () => {
      pos.current.x += (target.current.x - pos.current.x) * 0.18;
      pos.current.y += (target.current.y - pos.current.y) * 0.18;
      if (ringRef.current) ringRef.current.style.transform = `translate3d(${pos.current.x}px, ${pos.current.y}px, 0) translate(-50%, -50%)`;
      if (dotRef.current) dotRef.current.style.transform = `translate3d(${target.current.x}px, ${target.current.y}px, 0) translate(-50%, -50%)`;
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => { cancelAnimationFrame(raf); window.removeEventListener("pointermove", onMove); };
  }, []);

  React.useEffect(() => {
    const onOver = (e) => {
      const el = e.target.closest("[data-cursor]");
      if (el) setMode("is-" + el.getAttribute("data-cursor"));
      else if (e.target.closest("a, button")) setMode("is-link");
      else setMode("");
    };
    document.addEventListener("pointerover", onOver);
    return () => document.removeEventListener("pointerover", onOver);
  }, []);

  return { ringRef, dotRef, mode };
}

function Cursor({ showNative }) {
  const { ringRef, dotRef, mode } = useCursor(showNative);
  return (
    <React.Fragment>
      <div ref={dotRef} className="cursor-dot" />
      <div ref={ringRef} className={"cursor-ring " + mode}>
        {mode === "is-view"    ? "VIEW"
         : mode === "is-drag"    ? "DRAG"
         : mode === "is-explore" ? <span className="cursor-ring__explore">↗<small>EXPLORE</small></span>
         : ""}
      </div>
    </React.Fragment>
  );
}

/* --- Text scramble on hover --- */
function Scramble({ children, className = "" }) {
  const ref = React.useRef(null);
  const original = React.useRef(typeof children === "string" ? children : "");
  const rafRef = React.useRef(0);
  const chars = "!<>-_\\/[]{}—=+*^?#________";

  const scramble = () => {
    const txt = original.current;
    let frame = 0;
    const total = 18;
    cancelAnimationFrame(rafRef.current);
    const step = () => {
      let out = "";
      for (let i = 0; i < txt.length; i++) {
        const reveal = frame / total > i / txt.length;
        if (reveal) out += txt[i];
        else out += txt[i] === " " ? " " : chars[(Math.random() * chars.length) | 0];
      }
      if (ref.current) ref.current.textContent = out;
      frame++;
      if (frame <= total + 4) rafRef.current = requestAnimationFrame(step);
      else if (ref.current) ref.current.textContent = txt;
    };
    step();
  };

  return (
    <span
      ref={ref}
      className={"scramble " + className}
      onPointerEnter={scramble}
    >{original.current}</span>
  );
}

/* --- Magnetic attraction --- */
function useMagnetic(strength = 0.35) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      const dx = (e.clientX - cx) * strength;
      const dy = (e.clientY - cy) * strength;
      el.style.transform = `translate(${dx}px, ${dy}px)`;
    };
    const onLeave = () => { el.style.transform = ""; };
    el.addEventListener("pointermove", onMove);
    el.addEventListener("pointerleave", onLeave);
    return () => {
      el.removeEventListener("pointermove", onMove);
      el.removeEventListener("pointerleave", onLeave);
    };
  }, [strength]);
  return ref;
}

/* --- Reveal on scroll --- */
function useReveal() {
  React.useEffect(() => {
    const els = document.querySelectorAll(".reveal");
    const io = new IntersectionObserver((entries) => {
      entries.forEach(en => { if (en.isIntersecting) { en.target.classList.add("in"); io.unobserve(en.target); } });
    }, { threshold: 0.12 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  });
}

/* --- Scroll progress --- */
function ScrollProgress() {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const on = () => {
      const h = document.documentElement;
      const p = h.scrollTop / Math.max(1, h.scrollHeight - h.clientHeight);
      if (ref.current) ref.current.style.width = (p * 100) + "%";
    };
    on();
    window.addEventListener("scroll", on, { passive: true });
    return () => window.removeEventListener("scroll", on);
  }, []);
  return <div ref={ref} className="scroll-progress" />;
}

Object.assign(window, { Cursor, Scramble, useMagnetic, useReveal, ScrollProgress });
