"use client";

import { useEffect, useRef } from "react";

/**
 * Animates a number from 0 to `value` once it scrolls into view (cubic ease-out,
 * ~1.3s), matching the design's count-up script. Renders the final value
 * immediately under reduced motion.
 */
export function CountUp({
  value,
  prefix = "",
  suffix = "",
  dec = 0,
  className,
}: {
  value: number;
  prefix?: string;
  suffix?: string;
  dec?: number;
  className?: string;
}) {
  const ref = useRef<HTMLSpanElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    const render = (n: number) => {
      el.textContent = `${prefix}${n.toFixed(dec)}${suffix}`;
    };

    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      render(value);
      return;
    }

    let raf = 0;
    const io = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (!entry.isIntersecting) continue;
          io.unobserve(el);
          const dur = 1300;
          let t0: number | null = null;
          const step = (ts: number) => {
            if (t0 === null) t0 = ts;
            const p = Math.min((ts - t0) / dur, 1);
            const eased = 1 - Math.pow(1 - p, 3);
            render(value * eased);
            if (p < 1) raf = requestAnimationFrame(step);
            else render(value);
          };
          raf = requestAnimationFrame(step);
        }
      },
      { threshold: 0.5 },
    );
    io.observe(el);
    return () => {
      io.disconnect();
      cancelAnimationFrame(raf);
    };
  }, [value, prefix, suffix, dec]);

  return (
    <span ref={ref} className={className}>
      {prefix}
      {(0).toFixed(dec)}
      {suffix}
    </span>
  );
}
