import React, { useEffect, useRef } from 'react';
import { Animated, Easing, StyleSheet } from 'react-native';
import type { StyleProp, ViewStyle, ViewProps } from 'react-native';
import {
  StyledLoadingDot,
  StyledLoadingIndicatorWrapper,
} from './StyledLoadingIndicator';

type ThemeVariant =
  | 'basic-transparent'
  | 'filled-primary'
  | 'filled-secondary'
  | 'filled-danger'
  | 'filled-white'
  | 'filled-inverted'
  | 'outlined-primary'
  | 'outlined-secondary'
  | 'outlined-danger'
  | 'outlined-white'
  | 'outlined-inverted'
  | 'text-primary'
  | 'text-secondary'
  | 'text-danger'
  | 'text-white'
  | 'text-inverted';

const AnimatedLoadingIndicatorWrapper = Animated.createAnimatedComponent(
  StyledLoadingIndicatorWrapper
);

const AnimatedLoadingDot = Animated.createAnimatedComponent(StyledLoadingDot);

const renderDotComponent = ({
  index,
  size,
  count,
  animation,
  themeVariant,
}: {
  index: number;
  size: number;
  count: number;
  animation: React.MutableRefObject<Animated.Value>;
  themeVariant: ThemeVariant;
}) => {
  const interpolatedProgressAnimation = animation.current.interpolate({
    inputRange: [
      0.0,
      (index + 0.5) / (count + 1),
      (index + 1.0) / (count + 1),
      (index + 1.5) / (count + 1),
      1.0,
    ],
    outputRange: [1.0, 1.36, 1.56, 1.06, 1.0],
  });

  return (
    <Animated.View
      style={StyleSheet.flatten([
        {
          transform: [
            {
              scale: interpolatedProgressAnimation,
            },
          ],
        },
      ])}
      {...{ key: index }}
    >
      <AnimatedLoadingDot size={size} themeVariant={themeVariant} />
    </Animated.View>
  );
};

interface LoadingIndicatorProps extends ViewProps {
  /**
   * Size of the loading dot.
   */
  count?: number;
  /**
   * Size of the loading dot.
   */
  size?: number;
  /**
   * Additional style.
   */
  style?: StyleProp<ViewStyle>;
  /**
   * Testing id of the component.
   */
  testID?: string;
  /**
   * Testing id of the component.
   */
  themeVariant: ThemeVariant;
}

const LoadingIndicator = ({
  count = 3,
  size = 12,
  testID,
  themeVariant,
  ...nativeProps
}: LoadingIndicatorProps) => {
  const progressAnimation = useRef<Animated.Value>(new Animated.Value(0));

  useEffect(() => {
    const animation = Animated.loop(
      Animated.timing(progressAnimation.current, {
        toValue: 1,
        duration: 1200,
        easing: Easing.linear,
        useNativeDriver: true,
      })
    );

    animation.start();

    return () => {
      animation.stop();
    };
  }, []);

  const renderLoadingDot = (_item: any, index: number) => {
    if (typeof renderDotComponent === 'function') {
      return renderDotComponent({
        index,
        count,
        size,
        animation: progressAnimation,
        themeVariant,
      });
    }

    return null;
  };

  return (
    <AnimatedLoadingIndicatorWrapper testID={testID} {...nativeProps}>
      {Array.from(new Array(count), renderLoadingDot, themeVariant)}
    </AnimatedLoadingIndicatorWrapper>
  );
};

export default LoadingIndicator;
