"use client";

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

/**
 * Number that ticks up from 0 → `value` when scrolled into view.
 * Uses requestAnimationFrame only (no animation library).
 *
 * CUSTOMIZATION HOOK — CONTENT: value / prefix / suffix.
 */
export default function Counter({
  value,
  duration = 1600,
  prefix = "",
  suffix = "",
  className = "",
  static: isStatic = false,
}: {
  value: number;
  duration?: number;
  prefix?: string;
  suffix?: string;
  className?: string;
  /** Render the value as plain text (no tick animation). Use for years,
      dates, or any value that should not be perceived as "counting up".
      See LAYOUT_AUDIT #11. */
  static?: boolean;
}) {
  const ref = useRef<HTMLSpanElement>(null);
  const [display, setDisplay] = useState(isStatic ? value : 0);

  useEffect(() => {
    // When `static` is set, the value is rendered as-is with no observer.
    if (isStatic) return;
    const el = ref.current;
    if (!el) return;

    const prefersReduced = window.matchMedia(
      "(prefers-reduced-motion: reduce)"
    ).matches;

    // Hoisted to the effect scope so the cleanup below can cancel an
    // in-flight frame on unmount / dep change (the IO callback's own
    // return value is never used as a cleanup).
    let raf = 0;

    const io = new IntersectionObserver(
      ([entry]) => {
        if (!entry.isIntersecting) return;
        io.disconnect();

        if (prefersReduced) {
          setDisplay(value);
          return;
        }

        const start = performance.now();
        const tick = (now: number) => {
          const t = Math.min((now - start) / duration, 1);
          // easeOutExpo
          const eased = t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
          setDisplay(Math.round(eased * value));
          if (t < 1) raf = requestAnimationFrame(tick);
        };
        raf = requestAnimationFrame(tick);
      },
      { threshold: 0.4 }
    );

    io.observe(el);
    return () => {
      io.disconnect();
      cancelAnimationFrame(raf);
    };
  }, [value, duration, isStatic]);

  return (
    <span ref={ref} className={`tabular-nums ${className}`}>
      {prefix}
      {display}
      {suffix}
    </span>
  );
}
