import React, {useCallback, useEffect, useRef, useState} from 'react';
import {FlatList, View} from 'react-native';
import {PhotoIdentifier} from '@react-native-camera-roll/camera-roll';
import Animated, {
  useAnimatedStyle,
  withTiming,
  SharedValue,
  useSharedValue,
  withSpring,
  useDerivedValue,
  interpolate,
  Extrapolation,
  withDelay,
  runOnJS,
} from 'react-native-reanimated';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';

import {useRecentMedia} from '../../../../hooks/media/useRecentMedia';
import {MediaCarouselItem} from '../MediaCarouselItem';
import {styles, CAROUSEL_HEIGHT, HANDLE_HEIGHT} from './styles';

interface MediaCarouselProps {
  onMediaPress: (item: PhotoIdentifier) => void;
  isRecordingSV?: SharedValue<number>;
  bottomPadding?: SharedValue<number>;
  isFront?: boolean;
}

export const MediaCarousel: React.FC<MediaCarouselProps> = ({
  onMediaPress,
  isRecordingSV,
  bottomPadding,
  isFront,
}) => {
  const {media, loading, hasPermission} = useRecentMedia(20);
  const isExpanded = useSharedValue(1);
  const translateY = useSharedValue(0);
  const startY = useSharedValue(0);
  const isGestureActive = useRef(false);
  const [isOverflowVisible, setIsOverflowVisible] = useState(true);
  const opacity = useDerivedValue(() => {
    if (!bottomPadding) {
      return 0;
    }
    return interpolate(
      bottomPadding.value,
      [0, bottomPadding.value],
      [0, 1],
      Extrapolation.CLAMP,
    );
  }, [translateY]);

  const renderItem = useCallback(
    ({item}: {item: PhotoIdentifier}) => (
      <MediaCarouselItem
        item={item}
        onPress={onMediaPress}
        isExpanded={isExpanded}
      />
    ),
    [onMediaPress, isExpanded],
  );

  const keyExtractor = useCallback(
    (item: PhotoIdentifier) => item.node.image.uri,
    [],
  );

  const setGestureActive = (value: boolean) => {
    isGestureActive.current = value;
  };

  const setOverflowVisibleIfNoGesture = () => {
    if (!isGestureActive.current) {
      setIsOverflowVisible(true);
    }
  };

  const panGesture = Gesture.Pan()
    .onBegin(() => {
      runOnJS(setGestureActive)(true);
      startY.value = translateY.value;
      runOnJS(setIsOverflowVisible)(false);
    })
    .onUpdate(event => {
      const newTranslateY = startY.value + event.translationY;
      if (newTranslateY >= 0 && newTranslateY <= CAROUSEL_HEIGHT) {
        translateY.value = newTranslateY;
      }
    })
    .onEnd(event => {
      const threshold = CAROUSEL_HEIGHT / 2;
      const shouldCollapse = event.translationY > threshold;
      runOnJS(setGestureActive)(false);

      if (shouldCollapse) {
        translateY.value = withSpring(CAROUSEL_HEIGHT - HANDLE_HEIGHT, {
          damping: 50,
          stiffness: 200,
        });
        isExpanded.value = 0;
      } else {
        isExpanded.value = 1;
        translateY.value = withSpring(0, {damping: 20, stiffness: 200}, () => {
          runOnJS(setOverflowVisibleIfNoGesture)();
        });
      }
    });

  const hideAnimatedStyle = useAnimatedStyle(() => {
    const recordingOpacity = isRecordingSV && isRecordingSV.value === 1 ? 0 : 1;
    const finalOpacity = Math.min(opacity.value, recordingOpacity);

    return {
      bottom: withTiming(bottomPadding ? bottomPadding.value : 0),
      opacity: withDelay(200, withTiming(finalOpacity, {duration: 200})),
    };
  });

  const carouselAnimatedStyle = useAnimatedStyle(() => ({
    transform: [{translateY: translateY.value}],
  }));

  useEffect(() => {
    if (isFront) {
      setIsOverflowVisible(false);
      translateY.value = withTiming(CAROUSEL_HEIGHT - HANDLE_HEIGHT, {
        duration: 300,
      });
      isExpanded.value = 0;
    }
  }, [isExpanded, isFront, translateY]);

  if (loading || !hasPermission || media.length === 0) {
    return null;
  }

  const overflowStyle = {
    overflow: isOverflowVisible ? 'visible' : 'hidden',
  } as const;

  return (
    <Animated.View style={[styles.container, hideAnimatedStyle, overflowStyle]}>
      <Animated.View style={[styles.carouselWrapper, carouselAnimatedStyle]}>
        <GestureDetector gesture={panGesture}>
          <View style={styles.handleContainer}>
            <View style={styles.handle} />
          </View>
        </GestureDetector>
        <FlatList
          data={media}
          renderItem={renderItem}
          keyExtractor={keyExtractor}
          horizontal
          showsHorizontalScrollIndicator={false}
          style={styles.flatList}
          contentContainerStyle={styles.contentContainer}
        />
      </Animated.View>
    </Animated.View>
  );
};
