import React, {
  useState,
  useRef,
  useImperativeHandle,
  forwardRef,
  useCallback,
} from 'react';
import {
  View,
  Animated,
  PanResponder,
  StyleSheet,
  Dimensions,
} from 'react-native';

type BottomSheetProps = {
  children: React.ReactNode;
  onClose?: () => void;
  snapPoints?: string[];
};

export type BottomSheetHandle = {
  open: () => void;
  close: (doNotTriggerCallback?: boolean) => void;
  opened: boolean;
};

const BottomSheet = forwardRef<BottomSheetHandle, BottomSheetProps>(
  ({children, onClose, snapPoints}, ref) => {
    const screenHeight = Dimensions.get('window').height;
    const [height] = useState(new Animated.Value(0));
    const [isVisible, setIsVisible] = useState(false);
    const [currentSnapPointIndex, setCurrentSnapPointIndex] = useState(0);
    const validSnapPoints =
      snapPoints && snapPoints.length > 0 ? snapPoints : ['60%'];

    const snapPointsInPixels = validSnapPoints.map(snapPoint => {
      const percentageValue = parseFloat(snapPoint) / 100;
      return screenHeight * percentageValue;
    });

    const openBottomSheet = useCallback(() => {
      setIsVisible(true);
      let nextSnapPointIndex =
        (currentSnapPointIndex + 1) % validSnapPoints.length; // Cycle through snap points
      setCurrentSnapPointIndex(nextSnapPointIndex);

      Animated.timing(height, {
        toValue: snapPointsInPixels[nextSnapPointIndex],
        duration: 300,
        useNativeDriver: false,
      }).start();
    }, [
      currentSnapPointIndex,
      validSnapPoints.length,
      height,
      snapPointsInPixels,
    ]);

    const closeBottomSheet = useCallback(
      (doNotTriggerCallback?: boolean) => {
        Animated.timing(height, {
          toValue: 0,
          duration: 300,
          useNativeDriver: false,
        }).start(() => {
          setIsVisible(false);
          if (onClose && !doNotTriggerCallback) {
            onClose();
          } // Call the onClose callback
        });
      },
      [height, onClose],
    );

    useImperativeHandle(
      ref,
      () => ({
        open: openBottomSheet,
        close: doNotTriggerCallback => {
          console.log(doNotTriggerCallback);
          closeBottomSheet(doNotTriggerCallback);
        },
        opened: isVisible,
      }),
      [closeBottomSheet, isVisible, openBottomSheet],
    );

    // Updated PanResponder within the BottomSheet component

    const panResponder = useRef(
      PanResponder.create({
        onStartShouldSetPanResponder: () => true,
        onPanResponderMove: (e, gestureState) => {
          // Directly using dy to adjust the height can cause inverted behavior
          // because the gesture dy is positive when moving down, and negative when moving up,
          // which is the opposite of how we visually perceive the bottom sheet's "height" changing.

          if (isVisible) {
            // Calculate the new height based on the gesture movement
            const newHeight =
              gestureState.dy > 0
                ? Math.max(
                    snapPointsInPixels[currentSnapPointIndex] - gestureState.dy,
                    0,
                  ) // Moving down reduces height
                : Math.min(
                    snapPointsInPixels[currentSnapPointIndex] - gestureState.dy,
                    snapPointsInPixels[snapPointsInPixels.length - 1],
                  ); // Moving up increases height but caps at the max height

            // Apply the new height immediately to follow the finger
            height.setValue(newHeight);
          }
        },
        onPanResponderRelease: (e, gestureState) => {
          // Determine the final action based on the gesture velocity and direction
          if (gestureState.vy > 0.5 || gestureState.dy > 0) {
            // Quick or significant move down: Close the bottom sheet
            closeBottomSheet();
          } else if (gestureState.vy < -0.5 || gestureState.dy < 0) {
            // Quick or significant move up: Open to the next snap point
            const nextSnapPointIndex =
              (currentSnapPointIndex + 1) % snapPointsInPixels.length;
            setCurrentSnapPointIndex(nextSnapPointIndex);

            // Animate to the next snap point's height
            Animated.timing(height, {
              toValue: snapPointsInPixels[nextSnapPointIndex],
              duration: 300,
              useNativeDriver: false,
            }).start();
          } else {
            // Otherwise, revert to the nearest snap point based on the ending position
            // This can be enhanced to calculate the nearest snap point dynamically
            Animated.spring(height, {
              toValue: snapPointsInPixels[currentSnapPointIndex],
              useNativeDriver: false,
            }).start();
          }
        },
      }),
    ).current;

    return (
      <Animated.View style={[styles.bottomSheet, {height}]}>
        <View style={styles.handleHitBox} {...panResponder.panHandlers}>
          {/* Inner View for visual decoration */}
          <View style={styles.handle} />
        </View>
        {children}
      </Animated.View>
    );
  },
);

const styles = StyleSheet.create({
  bottomSheet: {
    position: 'absolute',
    zIndex: 1000,
    bottom: 0,
    alignSelf: 'center',
    width: '100%',
    backgroundColor: 'whitesmoke',
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
    paddingHorizontal: 10,
    // ...other styling for the bottom sheet
  },
  handle: {
    width: 40,
    height: 5,
    backgroundColor: 'grey',
    borderRadius: 2.5,
    alignSelf: 'center',
    marginTop: 8,
    // ...other styling for the handle
  },
  handleHitBox: {
    width: '100%', // Larger hitbox width
    height: 40, // Larger hitbox height
    justifyContent: 'center',
    alignItems: 'center',
    // No backgroundColor needed, it's just for increasing the touchable area
  },
});

export default BottomSheet;
