"use client";

import * as React from "react";
import { cn } from "@/lib/utils";

interface AnimatedCounterProps {
  value: number;
  suffix?: string;
  duration?: number;
  className?: string;
}

function AnimatedCounter({ value, suffix = "", duration = 2000, className }: AnimatedCounterProps) {
  const [displayValue, setDisplayValue] = React.useState(value);
  const hasAnimated = React.useRef(false);
  const ref = React.useRef<HTMLSpanElement>(null);

  React.useEffect(() => {
    const element = ref.current;
    if (!element) return;

    // Initial render already shows the final value (SSR/SEO-safe); with
    // reduced motion we keep it and skip the count-up entirely.
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          observer.disconnect();
          if (hasAnimated.current) {
            // Effect re-ran after the count-up already played (value/duration
            // prop change) — show the final value instead of replaying.
            setDisplayValue(value);
            return;
          }
          hasAnimated.current = true;

          const start = performance.now();
          const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);

          const tick = (now: number) => {
            const elapsed = now - start;
            const progress = Math.min(elapsed / duration, 1);
            setDisplayValue(Math.round(easeOutCubic(progress) * value));
            if (progress < 1) {
              requestAnimationFrame(tick);
            }
          };
          requestAnimationFrame(tick);
        }
      },
      { threshold: 0.1 }
    );

    observer.observe(element);
    return () => observer.disconnect();
  }, [value, duration]);

  return (
    <span ref={ref} className={cn("tabular-nums", className)}>
      {displayValue}
      {suffix}
    </span>
  );
}

export { AnimatedCounter };
