const { useState: useStateCU, useRef: useRefCU, useEffect: useEffectCU } = React;

/* Scroll-triggered count-up. Animates 0 → end when it scrolls into view.
   Honors prefers-reduced-motion (snaps to final value). */
function CountUp({ end, decimals = 0, duration = 1500 }) {
  const [val, setVal] = useStateCU(0);
  const ref = useRefCU(null);
  const done = useRefCU(false);

  useEffectCU(() => {
    const node = ref.current;
    if (!node) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduce) { setVal(end); return; }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !done.current) {
          done.current = true;
          const t0 = performance.now();
          const tick = (now) => {
            const t = Math.min(1, (now - t0) / duration);
            const eased = 1 - Math.pow(1 - t, 3); // easeOutCubic
            setVal(end * eased);
            if (t < 1) requestAnimationFrame(tick);
            else setVal(end);
          };
          requestAnimationFrame(tick);
          // Safety net: if rAF is throttled (e.g. background tab), still land on the final value.
          setTimeout(() => setVal(end), duration + 250);
        }
      });
    }, { threshold: 0.5 });

    io.observe(node);
    return () => io.disconnect();
  }, [end, duration]);

  const display = decimals > 0 ? val.toFixed(decimals) : Math.round(val).toString();
  return <span ref={ref}>{display}</span>;
}
window.CountUp = CountUp;
