/**
 * Hook for animating numbers with easing.
 * Creates smooth counting animation from 0 to target value.
 */

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

interface UseAnimatedNumberOptions {
  duration?: number;
  delay?: number;
  decimals?: number;
  easing?: (t: number) => number;
}

// Easing functions
const easings = {
  easeOutExpo: (t: number) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)),
  easeOutCubic: (t: number) => 1 - Math.pow(1 - t, 3),
  easeOutQuart: (t: number) => 1 - Math.pow(1 - t, 4),
};

export function useAnimatedNumber(
  targetValue: number,
  options: UseAnimatedNumberOptions = {}
): number {
  const {
    duration = 1500,
    delay = 0,
    decimals = 0,
    easing = easings.easeOutExpo,
  } = options;

  const [displayValue, setDisplayValue] = useState(0);
  const startTimeRef = useRef<number | null>(null);
  const startValueRef = useRef(0);
  const frameRef = useRef<number>();

  useEffect(() => {
    // Store starting value for smooth transitions
    startValueRef.current = displayValue;
    startTimeRef.current = null;

    const animate = (currentTime: number) => {
      if (startTimeRef.current === null) {
        startTimeRef.current = currentTime + delay;
      }

      const elapsed = currentTime - startTimeRef.current;

      if (elapsed < 0) {
        frameRef.current = requestAnimationFrame(animate);
        return;
      }

      const progress = Math.min(elapsed / duration, 1);
      const easedProgress = easing(progress);

      const currentValue =
        startValueRef.current + (targetValue - startValueRef.current) * easedProgress;

      setDisplayValue(
        decimals > 0
          ? parseFloat(currentValue.toFixed(decimals))
          : Math.round(currentValue)
      );

      if (progress < 1) {
        frameRef.current = requestAnimationFrame(animate);
      }
    };

    frameRef.current = requestAnimationFrame(animate);

    return () => {
      if (frameRef.current) {
        cancelAnimationFrame(frameRef.current);
      }
    };
  }, [targetValue, duration, delay, decimals, easing]);

  return displayValue;
}

/**
 * Format large numbers with animated counting.
 */
export function useAnimatedCompact(
  value: number,
  options: UseAnimatedNumberOptions = {}
): string {
  const animatedValue = useAnimatedNumber(value, options);

  if (animatedValue >= 1_000_000_000) {
    return `${(animatedValue / 1_000_000_000).toFixed(2)}B`;
  }
  if (animatedValue >= 1_000_000) {
    return `${(animatedValue / 1_000_000).toFixed(2)}M`;
  }
  if (animatedValue >= 1_000) {
    return `${(animatedValue / 1_000).toFixed(2)}K`;
  }
  return animatedValue.toLocaleString();
}

export default useAnimatedNumber;
