import React, { memo, useMemo } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  useSharedValue,
  withRepeat,
  withTiming,
  useAnimatedReaction,
  useDerivedValue,
  useAnimatedStyle,
  Easing,
} from 'react-native-reanimated';
import { useLayout, useGetBones } from 'react-native-reanimated-skeleton/lib/hooks';
import TextView from './TextView';

export const ANIMATION_TYPE = {
  NONE: "none",
  SHIVER: "shiver",
  PULSE: "pulse"
}

export const ANIMATION_DIRECTION = {
  HORIZONTAL_LEFT: "horizontalLeft",
  HORIZONTAL_RIGHT: "horizontalRight",
  VERTICAL_TOP: "verticalTop",
  VERTICAL_DOWN: "verticalDown",
  DIAGONAL_DOWN_LEFT: "diagonalDownLeft",
  DIAGONAL_DOWN_RIGHT: "diagonalDownRight",
  DIAGONAL_TOP_LEFT: "diagonalTopLeft",
  DIAGONAL_TOP_RIGHT: "diagonalTopRight"
}

const VbeSkeleton = ({
  style=styles.container,
  viewStyle={},
  textStyle={},
  text,
  duration=1200,
  layout=[],
  numberOfLines,
  animationType=ANIMATION_TYPE.SHIVER,
  animationDirection=ANIMATION_DIRECTION.HORIZONTAL_RIGHT,
  easing=Easing.bezier(0.5, 0, 0.25, 1),
  isLoading=true,
  boneColor='#eeeeee',
  highlightColor='#f6f6f6',
  hasFadeIn=false,
  children
}) => {
  const animationValue = useSharedValue(0);
  const loadingValue = useSharedValue(0);
  const shiverValue = useSharedValue(animationType === 'shiver' ? 1 : 0);
  const [componentSize, onLayout] = useLayout();
  const generalStyles = useMemo(
    () => ({
      animationDirection,
      animationType,
      boneColor,
      animationValue,
      highlightColor,
    }),
    [
      animationDirection,
      animationType,
      animationValue,
      boneColor,
      highlightColor,
    ],
  );

  const getBones = useGetBones(componentSize);

  useAnimatedReaction(
    () => ({ isLoading, loadingValue }),
    () => {
      if (isLoading && loadingValue.value !== 1) {
        /* NOTE: Reset behaviour to ensure animation always starts from the beginning */
        animationValue.value = 0;

        animationValue.value =
          shiverValue.value === 1
            ? withRepeat(withTiming(1, { duration, easing }), -1, false)
            : withRepeat(
                withTiming(1, { duration: duration / 2, easing }),
                -1,
                true,
              );
      }
    },
    [isLoading, shiverValue],
  );

  const opacity = useDerivedValue(() => {
    if (!isLoading) {
      return withTiming(1, { duration: 250 });
    }

    return 0;
  });

  const animatedStyle = useAnimatedStyle(() => ({
    opacity: opacity.value,
  }));

  return (
    <View style={style} onLayout={onLayout}>
      {isLoading ? (
        getBones({
          bonesLayout: layout,
          children,
          generalStyles,
        })
      ) : (
        <Animated.View style={[viewStyle, hasFadeIn ? animatedStyle : {}]}>
          { text
          ? <TextView style={textStyle} numberOfLines={numberOfLines}>{text}</TextView>
          : children
          }
        </Animated.View>
      )}
    </View>
  );
};

export default VbeSkeleton;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center'
  },
  viewStyle: {
    alignItems: 'center'
  }
});