// Shared utilities

const { useState, useEffect, useRef, useCallback, useMemo } = React;

// Reveal-on-scroll observer
function useReveal(rootMargin = "-10% 0px") {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal");
    if (!("IntersectionObserver" in window)) {
      els.forEach(el => el.classList.add("visible"));
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add("visible");
            io.unobserve(e.target);
          }
        });
      },
      { rootMargin, threshold: 0.05 }
    );
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);
}

// Animated number counter
function AnimatedNumber({ to, duration = 1800, suffix = "", prefix = "" }) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const started = useRef(false);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const start = performance.now();
          const tick = (now) => {
            const t = Math.min(1, (now - start) / duration);
            const eased = 1 - Math.pow(1 - t, 3);
            setVal(to * eased);
            if (t < 1) requestAnimationFrame(tick);
            else setVal(to);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, duration]);

  const displayVal = Number.isInteger(to) ? Math.round(val) : val.toFixed(1);
  return (
    <span ref={ref}>
      {prefix}{displayVal}<span className="unit">{suffix}</span>
    </span>
  );
}

// Word rotator for headline
function Rotator({ words, interval = 2400 }) {
  const [idx, setIdx] = useState(0);
  const [phase, setPhase] = useState("active"); // active | exit

  useEffect(() => {
    const timer = setTimeout(() => {
      setPhase("exit");
      const next = setTimeout(() => {
        setIdx((i) => (i + 1) % words.length);
        setPhase("active");
      }, 500);
      return () => clearTimeout(next);
    }, interval);
    return () => clearTimeout(timer);
  }, [idx, interval, words.length]);

  // Compute width based on longest word for stable layout
  const longest = useMemo(
    () => words.reduce((a, b) => (a.length > b.length ? a : b), ""),
    [words]
  );

  return (
    <span className="rotator" style={{ minWidth: `${longest.length * 0.55}em` }}>
      {words.map((w, i) => (
        <span
          key={w}
          className={i === idx ? phase : (i === (idx - 1 + words.length) % words.length && phase === "active") ? "exit" : ""}
        >
          {w}
        </span>
      ))}
    </span>
  );
}

Object.assign(window, { useReveal, AnimatedNumber, Rotator });
