/* global React */
// ============================================================
// MOTION PRIMITIVES — scroll reveals, counters, magnetic, split text
// ============================================================
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ── Intersection-based reveal hook ──────────────────────────
function useReveal(opts = {}) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setShown(true); obs.disconnect(); }
    }, { threshold: opts.threshold ?? 0.12, rootMargin: opts.rootMargin ?? "-40px 0px" });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  return [ref, shown];
}

// ── Reveal wrapper ──────────────────────────────────────────
function Reveal({ children, delay = 0, kind = "up", className = "", as: As = "div", style, ...rest }) {
  const [ref, shown] = useReveal();
  return (
    <As
      ref={ref}
      className={`reveal reveal--${kind} ${shown ? "reveal--in" : ""} ${className}`}
      style={{ transitionDelay: delay + "ms", ...style }}
      {...rest}
    >
      {children}
    </As>
  );
}

// ── Stagger children ────────────────────────────────────────
function Stagger({ children, step = 80, kind = "up", className = "" }) {
  const [ref, shown] = useReveal();
  const arr = React.Children.toArray(children);
  return (
    <div ref={ref} className={className}>
      {arr.map((child, i) => (
        <div
          key={i}
          className={`reveal reveal--${kind} ${shown ? "reveal--in" : ""}`}
          style={{ transitionDelay: (i * step) + "ms" }}
        >
          {child}
        </div>
      ))}
    </div>
  );
}

// ── Animated counter ────────────────────────────────────────
function Counter({ to, suffix = "", prefix = "", duration = 1400, format }) {
  const [ref, shown] = useReveal();
  const [n, setN] = useState(0);
  useEffect(() => {
    if (!shown) return;
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setN(eased * to);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [shown, to, duration]);
  const display = format ? format(n) : Math.floor(n);
  return <span ref={ref}>{prefix}{display}{suffix}</span>;
}

// ── Split title — word-by-word slide up ─────────────────────
function SplitTitle({ text, className = "", as: As = "h1", step = 50, accentWords = [] }) {
  const [ref, shown] = useReveal({ threshold: 0.05 });
  const tokens = String(text).split(/(\s+)/);
  let wordIdx = 0;
  return (
    <As ref={ref} className={`split ${shown ? "split--in" : ""} ${className}`}>
      {tokens.map((tok, i) => {
        if (/\s+/.test(tok)) return <span key={i}>{tok}</span>;
        const idx = wordIdx++;
        const isAccent = accentWords.includes(tok.replace(/[.,]/g, ""));
        return (
          <span key={i} className="split__w-outer">
            <span
              className={`split__w ${isAccent ? "split__w--em" : ""}`}
              style={{ transitionDelay: (idx * step) + "ms" }}
            >{tok}</span>
          </span>
        );
      })}
    </As>
  );
}

// ── Magnetic button wrapper ─────────────────────────────────
function Magnetic({ children, strength = 14, className = "" }) {
  const ref = useRef(null);
  const onMove = (e) => {
    const r = ref.current.getBoundingClientRect();
    const x = e.clientX - r.left - r.width / 2;
    const y = e.clientY - r.top - r.height / 2;
    ref.current.style.transform = `translate(${x / strength}px, ${y / strength}px)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ""; };
  return (
    <span ref={ref} onMouseMove={onMove} onMouseLeave={onLeave} className={`magnetic ${className}`}>
      {children}
    </span>
  );
}

// ── Scroll progress bar ─────────────────────────────────────
function ScrollProgress() {
  const [p, setP] = useState(0);
  useEffect(() => {
    const onScroll = () => {
      const h = document.documentElement;
      const denom = h.scrollHeight - h.clientHeight;
      setP(denom > 0 ? Math.min(1, Math.max(0, h.scrollTop / denom)) : 0);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return <div className="scroll-progress"><div className="scroll-progress__bar" style={{ transform: `scaleX(${p})` }} /></div>;
}

// ── Cursor-following spotlight ──────────────────────────────
function Spotlight({ selector }) {
  useEffect(() => {
    const el = document.querySelector(selector);
    if (!el) return;
    const move = (e) => {
      const r = el.getBoundingClientRect();
      el.style.setProperty("--mx", ((e.clientX - r.left) / r.width * 100) + "%");
      el.style.setProperty("--my", ((e.clientY - r.top) / r.height * 100) + "%");
    };
    el.addEventListener("mousemove", move);
    return () => el.removeEventListener("mousemove", move);
  }, [selector]);
  return null;
}

Object.assign(window, {
  useReveal, Reveal, Stagger, Counter, SplitTitle, Magnetic, ScrollProgress, Spotlight,
});
