import { useEffect, useRef, useState } from 'react';

function reducedMotion(): boolean {
    return (
        typeof window !== 'undefined' &&
        window.matchMedia('(prefers-reduced-motion: reduce)').matches
    );
}

/**
 * Rolls a number up from 0 to `value` on mount (~700ms, cubic ease-out).
 * `format` receives the in-flight integer — pass the same formatter the
 * static render used so the final frame is pixel-identical. Renders the
 * final value immediately for reduced-motion users.
 */
export function CountUp({
    value,
    format,
}: {
    value: number;
    format?: (n: number) => string;
}) {
    const [display, setDisplay] = useState(() => (reducedMotion() ? value : 0));
    const raf = useRef(0);

    useEffect(() => {
        if (reducedMotion()) {
            setDisplay(value);
            return;
        }
        const start = performance.now();
        const duration = 700;
        const tick = (now: number) => {
            const t = Math.min(1, (now - start) / duration);
            const eased = 1 - Math.pow(1 - t, 3);
            setDisplay(value * eased);
            if (t < 1) raf.current = requestAnimationFrame(tick);
        };
        raf.current = requestAnimationFrame(tick);
        return () => cancelAnimationFrame(raf.current);
    }, [value]);

    const n = Math.round(display);
    return <>{format ? format(n) : n.toLocaleString()}</>;
}
