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

import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { MusicNoteIcon } from '@/icons';
import { formatCredits } from '@/utils/utils';

interface CreditsCounterProps {
  creditsRemaining: number;
  onClick?: () => void;
  href?: string;
  onOutOfCreditsClick?: () => void;
}

const ANIMATION_DURATION = 500; // ms

const CreditsCounter: React.FC<CreditsCounterProps> = ({
  creditsRemaining,
  onClick,
  href,
  onOutOfCreditsClick,
}) => {
  const [displayValue, setDisplayValue] = useState(creditsRemaining);
  const formattedDisplayValue = useMemo(
    () => formatCredits(displayValue),
    [displayValue]
  );
  const rafRef = useRef<number | null>(null);
  const startValueRef = useRef(creditsRemaining);
  const startTimeRef = useRef<number>(0);

  const isOutOfCredits = creditsRemaining <= 0;

  // Calculate the max digit length (including commas) for the current and target value
  const maxDigits = useMemo(() => {
    // You can adjust this logic if you want to always reserve space for a certain max (e.g., 99999)
    return formattedDisplayValue.length;
  }, [formattedDisplayValue]);

  // Estimate width: 1ch per character, plus a little extra for spacing
  const numberWidth = `${maxDigits}ch`;

  useEffect(() => {
    if (displayValue === creditsRemaining) return;
    if (rafRef.current) cancelAnimationFrame(rafRef.current);
    startValueRef.current = displayValue;
    startTimeRef.current = performance.now();

    const animate = (now: number) => {
      const elapsed = now - startTimeRef.current;
      const progress = Math.min(elapsed / ANIMATION_DURATION, 1);
      const newValue = Math.round(
        startValueRef.current +
          (creditsRemaining - startValueRef.current) * progress
      );
      setDisplayValue(newValue);
      if (progress < 1) {
        rafRef.current = requestAnimationFrame(animate);
      } else {
        rafRef.current = null;
      }
    };
    rafRef.current = requestAnimationFrame(animate);
    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [creditsRemaining]);

  const isClickable =
    onClick || href || (isOutOfCredits && onOutOfCreditsClick);

  return (
    <Tooltip
      label={
        isOutOfCredits
          ? 'Out of credits. Click to upgrade to Pro.'
          : `Credits remaining: ${creditsRemaining.toLocaleString()}`
      }
      placement='bottom'
    >
      <Button
        variant={
          isOutOfCredits ? ButtonVariant.Primary : ButtonVariant.Secondary
        }
        shape={ButtonShape.Pill}
        className={`px-3 transition-all duration-200 ${!isClickable ? 'cursor-default' : ''} ${
          isOutOfCredits
            ? 'bg-accent-error text-white shadow-lg hover:bg-accent-error/90'
            : ''
        }`}
        aria-label={`Credits remaining: ${creditsRemaining}`}
        {...(isOutOfCredits && onOutOfCreditsClick
          ? { onClick: onOutOfCreditsClick }
          : onClick
            ? { onClick }
            : {})}
        {...(href ? { href } : {})}
      >
        <span className='flex items-center'>
          <MusicNoteIcon style={{ fontSize: 18, marginRight: 0 }} />
          <span
            style={{
              fontWeight: 500,
              fontSize: 12,
              letterSpacing: 0.5,
              width: numberWidth,
              display: 'inline-block',
              textAlign: 'center',
              transition: 'width 0.2s',
            }}
          >
            {isOutOfCredits ? '0' : formattedDisplayValue}
          </span>
        </span>
      </Button>
    </Tooltip>
  );
};

export default CreditsCounter;
