import {ReactNode, useCallback, useEffect, useState} from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import {
  Easing,
  runOnJS,
  withDelay,
  withRepeat,
  withTiming,
  withSequence,
  useSharedValue,
  cancelAnimation,
  useAnimatedReaction,
} from 'react-native-reanimated';
import {Gradient, GradientProps} from '@components/_core/Gradient';

import {
  AI_BUTTON_GRADIENT_END,
  AI_BUTTON_GRADIENT_START,
  AI_BUTTON_GRADIENT_HOLD_MS,
  AI_BUTTON_GRADIENT_EXPAND_MS,
  AI_BUTTON_GRADIENT_LOCATIONS,
} from '../../constants';
import {getGradientLocations} from './utils';

const GRADIENT_EASING = Easing.bezier(0.25, 0.1, 0.25, 1);
const GRADIENT_TIMING = {
  duration: AI_BUTTON_GRADIENT_EXPAND_MS,
  easing: GRADIENT_EASING,
};

interface Props {
  isPressed: boolean;
  children: ReactNode;
  isAnimating: boolean;
  style?: StyleProp<ViewStyle>;
  defaultColors: GradientProps['colors'];
  pressedColors: GradientProps['colors'];
}

export function AnimatedAIGradient({
  style,
  children,
  isPressed,
  isAnimating,
  defaultColors,
  pressedColors,
}: Props) {
  const expandProgress = useSharedValue(0);
  const [locations, setLocations] = useState<GradientProps['locations']>(
    AI_BUTTON_GRADIENT_LOCATIONS,
  );

  const colors = isPressed ? pressedColors : defaultColors;

  const onExpandProgressChange = useCallback((progress: number) => {
    setLocations(getGradientLocations(progress));
  }, []);

  useEffect(() => {
    cancelAnimation(expandProgress);

    if (isAnimating) {
      expandProgress.value = withRepeat(
        withSequence(
          withTiming(1, GRADIENT_TIMING),
          withDelay(AI_BUTTON_GRADIENT_HOLD_MS, withTiming(0, GRADIENT_TIMING)),
        ),
        -1,
        false,
      );
    } else {
      expandProgress.value = withTiming(0, GRADIENT_TIMING);
    }

    return () => {
      cancelAnimation(expandProgress);
    };
  }, [expandProgress, isAnimating]);

  // expo-linear-gradient does not animate `locations` on the UI thread (useAnimatedProps
  // breaks the effect), so we bridge progress to JS and update React state instead.
  // runOnJS is deprecated in Reanimated 4 in favor of scheduleOnRN — same bridge pattern.
  useAnimatedReaction(
    () => expandProgress.value,
    progress => {
      runOnJS(onExpandProgressChange)(progress);
    },
    [expandProgress, onExpandProgressChange],
  );

  return (
    <Gradient
      style={style}
      colors={colors}
      locations={locations}
      end={AI_BUTTON_GRADIENT_END}
      start={AI_BUTTON_GRADIENT_START}>
      {children}
    </Gradient>
  );
}
