import {
  default as React,
  useContext,
  useEffect,
  useRef,
  useState,
} from 'react';
import {
  Animated,
  LayoutChangeEvent,
  StyleSheet,
  TouchableOpacity,
  View,
} from 'react-native';
import { ApplicationContext } from '../Context';
import { Icon } from '../Icon';

export interface FloatingButtonProps {
  label?: string;
  onPress?: () => void;
  position?: 'center' | 'right';
  icon?: string;
  iconColor?: string;
  size?: 'small' | 'large';
  animatedValue?: Animated.Value;
  bottom?: number;
  renderComponent?: () => React.ReactNode;
}

export const FloatingButton: React.FC<FloatingButtonProps> = ({
  renderComponent,
  label = '',
  onPress = () => {},
  position = 'right',
  icon = '',
  iconColor = '',
  size = 'small',
  animatedValue,
  bottom = 12,
}: FloatingButtonProps) => {
  const { theme } = useContext(ApplicationContext);
  const maxWidth = useRef(0);
  const minWidth = size === 'small' ? 36 : 48;
  const [opacityAnimated] = useState(new Animated.Value(0)); // Initial opacity set to 0
  const [widthAnimated, setWidthAnimated] = useState<Animated.Value>();
  const lastOffset = useRef(0);
  const lastDirection = useRef<string>(null);
  const [showText, setShowText] = React.useState(true);

  useEffect(() => {
    if (!label) return;

    Animated.timing(opacityAnimated, {
      toValue: 1,
      duration: 100,
      useNativeDriver: true,
    }).start();

    const listener = animatedValue?.addListener(({ value }) => {
      if (value !== lastOffset.current && value > 0) {
        const direction = value > lastOffset.current ? 'down' : 'up';
        lastOffset.current = value;
        if (lastDirection.current !== direction) {
          lastDirection.current = direction;
          if (direction === 'down') {
            Animated.timing(opacityAnimated, {
              toValue: 0,
              duration: 100,
              useNativeDriver: true,
            }).start();
            Animated.timing(widthAnimated!, {
              toValue: minWidth,
              duration: 100,
              useNativeDriver: false,
            }).start(() => setShowText(false));
          } else {
            Animated.timing(opacityAnimated, {
              toValue: 1,
              duration: 100,
              useNativeDriver: true,
            }).start();
            Animated.timing(widthAnimated!, {
              toValue: maxWidth.current,
              duration: 100,
              useNativeDriver: false,
            }).start(() => setShowText(true));
          }
        }
      }
    });

    return () => {
      if (listener) {
        animatedValue?.removeListener(listener);
      }
    };
  }, [animatedValue, label, minWidth, opacityAnimated, widthAnimated]);

  const handleLayout = (event: LayoutChangeEvent) => {
    const layout = event.nativeEvent.layout;
    if (widthAnimated) return;
    maxWidth.current = layout.width;
    setWidthAnimated(new Animated.Value(layout.width));
  };

  if (renderComponent) {
    return (
      <View
        onLayout={handleLayout}
        style={[
          styles.container,
          {
            right: position === 'right' ? 12 : undefined,
            alignSelf: position === 'center' ? 'center' : 'flex-end',
            bottom,
          },
        ]}
      >
        {renderComponent()}
      </View>
    );
  }

  return (
    <Animated.View
      onLayout={handleLayout}
      style={[
        styles.container,
        {
          right: position === 'right' ? 12 : undefined,
          alignSelf: position === 'center' ? 'center' : 'flex-end',
          width: widthAnimated,
          height: size === 'small' ? 36 : 48,
          backgroundColor: theme.colors.primary,
          bottom,
        },
      ]}
    >
      <TouchableOpacity
        style={{ flexDirection: 'row', alignItems: 'center' }}
        onPress={onPress}
      >
        <Icon
          source={icon}
          size={size === 'small' ? 12 : 24}
          color={iconColor}
        />
        {showText && !!label && (
          <Animated.Text
            allowFontScaling={false}
            style={[styles.label, { opacity: opacityAnimated, color: 'white' }]}
            numberOfLines={1}
          >
            {label}
          </Animated.Text>
        )}
      </TouchableOpacity>
    </Animated.View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignContent: 'center',
    alignItems: 'center',
    position: 'absolute',
    borderRadius: 100,
    paddingHorizontal: 12,
    flexWrap: 'wrap',
    alignSelf: 'flex-end',
  },
  label: {
    marginLeft: 8,
    fontSize: 16,
    lineHeight: 22,
    fontWeight: '700',
  },
});
