import React, { useEffect, useRef, useState } from 'react';
import { Animated, Easing, TextStyle } from 'react-native';

type AnimatedNumberProps = {
  value: number; // 最终值
  durationMs?: number;
  format?: (v: number) => string;
  style?: TextStyle;
  /** 当该值变化时，从0重新动画 */
  resetToken?: unknown;
};

export function AnimatedNumber({
  value,
  durationMs = 300,
  format,
  style,
  resetToken,
}: AnimatedNumberProps) {
  const opacity = useRef(new Animated.Value(1)).current;
  const [display, setDisplay] = useState<string>(() =>
    format ? format(value) : `${Math.round(value)}`
  );
  const [currentValue, setCurrentValue] = useState(value);
  const [lastResetToken, setLastResetToken] = useState(resetToken);
  const [isAnimating, setIsAnimating] = useState(false);

  useEffect(() => {
    // 检查是否需要触发动画
    const valueChanged = value !== currentValue;
    const resetTokenChanged = resetToken !== lastResetToken;

    // 如果值没有变化且resetToken也没有变化，或者正在动画中，则不执行新动画
    if ((!valueChanged && !resetTokenChanged) || isAnimating) {
      return;
    }

    // 标记开始动画
    setIsAnimating(true);

    // 停止当前动画
    opacity.stopAnimation(() => {
      // 创建优雅的透明度变化动画
      const fadeOut = Animated.timing(opacity, {
        toValue: 0.2, // 淡出到较低透明度
        duration: durationMs * 0.4, // 淡出占总时长的40%
        easing: Easing.out(Easing.quad),
        useNativeDriver: false,
      });

      const fadeIn = Animated.timing(opacity, {
        toValue: 1,
        duration: durationMs * 0.6, // 淡入占总时长的60%
        easing: Easing.out(Easing.quad),
        useNativeDriver: false,
      });

      // 在淡出完成时更新数字显示
      fadeOut.start(() => {
        // 更新当前值和显示
        setCurrentValue(value);
        setLastResetToken(resetToken);
        setDisplay(format ? format(value) : `${Math.round(value)}`);

        // 然后淡入新数字
        fadeIn.start(() => {
          // 动画完成，标记结束
          setIsAnimating(false);
        });
      });
    });
  }, [value, resetToken, currentValue, lastResetToken, isAnimating, durationMs, format]);

  return (
    <Animated.Text
      style={[
        style,
        {
          opacity: opacity
        }
      ]}
    >
      {display}
    </Animated.Text>
  );
}


