import React, {
  forwardRef,
  memo,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from "react";
import {
  Animated,
  Dimensions,
  Keyboard,
  Modal,
  PanResponder,
  StatusBar,
  StyleProp,
  StyleSheet,
  TouchableOpacity,
  View,
  ViewStyle,
} from "react-native";
import { verticalScale } from "../utils/styling";
import ChevronUpArrow from "../assets/svg/BottomSheet/chevronUpArrow";
import ChevronDownArrow from "../assets/svg/BottomSheet/ChevronDownArrow";

const { height: SCREEN_HEIGHT } = Dimensions.get("window");

export interface BottomSheetProps {
  snapPoints?: (string | number)[];
  openDuration?: number;
  closeDuration?: number;
  closeOnPressMask?: boolean;
  closeOnPressBack?: boolean;
  draggable?: boolean;
  dragOnContent?: boolean;
  onOpen?: (() => void) | null;
  onClose?: (() => void) | null;
  children?: React.ReactNode;
  mainContainer?: StyleProp<ViewStyle>;
  wrapperColors?: StyleProp<ViewStyle>;
  defaultOpen?: boolean; // <-- new prop
  showIndicator?: boolean; // if true, show the arrow/handle view
  statusBar?: boolean; // if true, show the status bar adjustment
  enableTouchThrough?: boolean;
  useModal?: boolean;
}

export interface BottomSheetHandle {
  open: () => void;
  close: () => void;
  snapToIndex: (index: number) => void;
}

const BottomSheet = forwardRef<BottomSheetHandle, BottomSheetProps>(
  (props, ref) => {
    const {
      snapPoints = ["30%"],
      openDuration = 350,
      closeDuration = 300,
      closeOnPressMask = true,
      closeOnPressBack = true,
      draggable = true,
      dragOnContent = true,
      onOpen,
      onClose,
      children,
      mainContainer = {},
      wrapperColors = {},
      defaultOpen = false, // <-- new default
      // showIndicator = true,
      statusBar = false,
      enableTouchThrough = false,
      useModal,
    } = props;

    const defaultHeight = 260;
    const [modalVisible, setModalVisible] = useState(false);
    const [isSnapping, setIsSnapping] = useState(false);

    const animatedHeight = useRef(new Animated.Value(0)).current;
    const keyboardPadding = useRef(new Animated.Value(0)).current;
    const startHeight = useRef(defaultHeight);
    const [dragDirection, setDragDirection] = useState<"up" | "down" | null>(
      null,
    );
    const indicatorOpacity = useRef(new Animated.Value(0)).current;

    // Keyboard adjustment
    useEffect(() => {
      const show = Keyboard.addListener("keyboardDidShow", (e) => {
        Animated.timing(keyboardPadding, {
          toValue: e.endCoordinates.height,
          duration: 150,
          useNativeDriver: false,
        }).start();
      });
      const hide = Keyboard.addListener("keyboardDidHide", () => {
        Animated.timing(keyboardPadding, {
          toValue: 0,
          duration: 150,
          useNativeDriver: false,
        }).start();
      });
      return () => {
        show.remove();
        hide.remove();
      };
    }, []);
    // Open automatically if defaultOpen is true
    useEffect(() => {
      if (defaultOpen) {
        setVisible(true);
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [defaultOpen]);

    useEffect(() => {
      if (!props.showIndicator) {
        Animated.timing(indicatorOpacity, {
          toValue: 0,
          duration: 200,
          useNativeDriver: true,
        }).start();
        return;
      }

      Animated.timing(indicatorOpacity, {
        toValue: 1,
        duration: 200,
        useNativeDriver: true,
      }).start();
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [dragDirection, props.showIndicator]);

    // Convert snap points to pixels
    const snapPointsPixels = useMemo(
      () =>
        snapPoints.map((p) =>
          typeof p === "string" && p.includes("%")
            ? (parseFloat(p) / 100) * SCREEN_HEIGHT
            : Number(p),
        ),
      [snapPoints],
    );

    const defaultSnap = snapPointsPixels[0] || defaultHeight;
    const maxSnap = Math.max(...snapPointsPixels);

    // Snap to index manually
    const snapToIndex = (index: number) => {
      const snapHeight = snapPointsPixels[index];
      if (!snapHeight) return;

      setIsSnapping(true);
      Animated.timing(animatedHeight, {
        toValue: snapHeight,
        duration: 250,
        useNativeDriver: false,
      }).start(() => setIsSnapping(false));
    };

    // useImperativeHandle(ref, () => ({
    //   open: () => setVisible(true),
    //   close: () => setVisible(false),
    //   snapToIndex,
    // }));
    useImperativeHandle(ref, () => ({
      open: () => {
        setModalVisible(true);
        onOpen?.();
        Animated.timing(animatedHeight, {
          toValue: defaultSnap,
          duration: openDuration,
          useNativeDriver: false,
        }).start(() => setIsSnapping(false));
      },

      close: () =>
        new Promise<void>((resolve) => {
          setIsSnapping(true);
          Animated.timing(animatedHeight, {
            toValue: 0,
            duration: closeDuration,
            useNativeDriver: false,
          }).start(() => {
            setModalVisible(false);
            setIsSnapping(false);
            onClose?.();
            resolve(); // 🔑 Android-safe
          });
        }),

      snapToIndex,
    }));
    // Pan responder for drag gestures
    const panResponder = useMemo(
      () =>
        PanResponder.create({
          onStartShouldSetPanResponder: () => draggable,
          onMoveShouldSetPanResponder: (_, g) =>
            draggable && dragOnContent && Math.abs(g.dy) > 3,
          onPanResponderGrant: () => {
            setIsSnapping(true);
            animatedHeight.stopAnimation((value) => {
              startHeight.current = value;
            });
          },
          onPanResponderMove: (_, gesture) => {
            const newHeight = startHeight.current - gesture.dy;
            animatedHeight.setValue(Math.max(0, Math.min(maxSnap, newHeight)));

            if (!props.showIndicator) return;

            if (gesture.dy > 0) setDragDirection("down");
            else if (gesture.dy < 0) setDragDirection("up");
          },
          onPanResponderRelease: (_, gesture) => {
            animatedHeight.stopAnimation((value) => {
              const currentHeight = value;
              const direction = gesture.dy > 0 ? "down" : "up";
              setDragDirection(null); // reset after release
              let targetSnap: number | undefined;

              if (direction === "down") {
                const below = snapPointsPixels.filter(
                  (p) => p <= currentHeight,
                );
                targetSnap =
                  below.length > 0
                    ? below.reduce((prev, curr) =>
                        Math.abs(curr - currentHeight) <
                        Math.abs(prev - currentHeight)
                          ? curr
                          : prev,
                      )
                    : Math.min(...snapPointsPixels);
              } else {
                const above = snapPointsPixels.filter(
                  (p) => p >= currentHeight,
                );
                targetSnap =
                  above.length > 0
                    ? above.reduce((prev, curr) =>
                        Math.abs(curr - currentHeight) <
                        Math.abs(prev - currentHeight)
                          ? curr
                          : prev,
                      )
                    : Math.max(...snapPointsPixels);
              }

              if (targetSnap === undefined) targetSnap = snapPointsPixels[0];

              Animated.spring(animatedHeight, {
                toValue: targetSnap,
                useNativeDriver: false,
              }).start(() => setIsSnapping(false));
            });
          },
        }),
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [draggable, dragOnContent, snapPointsPixels],
    );

    const setVisible = (visible: boolean) => {
      setIsSnapping(true);
      if (visible) {
        setModalVisible(true);
        onOpen?.();
        Animated.timing(animatedHeight, {
          toValue: defaultSnap,
          duration: openDuration,
          useNativeDriver: false,
        }).start(() => setIsSnapping(false));
      } else {
        Animated.timing(animatedHeight, {
          toValue: 0,
          duration: closeDuration,
          useNativeDriver: false,
        }).start(() => {
          setModalVisible(false);
          setIsSnapping(false);
          onClose?.();
        });
      }
    };

    return useModal ? (
      <Modal
        transparent
        animationType="fade"
        statusBarTranslucent
        visible={modalVisible}
        // onRequestClose={() => setVisible(false)}
        onRequestClose={() => {
          // Hardware back press on Android
          if (!modalVisible) {
            // Sheet is already closed, let back button work normally
            return;
          }

          if (closeOnPressBack) {
            // If prop allows closing, close the sheet
            setVisible(false);
          }
          // Else, do nothing: sheet stays open
          // This effectively blocks the hardware back
        }}
      >
        {modalVisible && statusBar && (
          <StatusBar
            backgroundColor="#828181"
            barStyle="light-content"
            animated
          />
        )}

        <View
          pointerEvents={enableTouchThrough ? "box-none" : "auto"}
          style={[styles.wrapper, wrapperColors]}
        >
          <TouchableOpacity
            style={styles.mask}
            activeOpacity={1}
            onPress={closeOnPressMask ? () => setVisible(false) : undefined}
          />

          <Animated.View
            {...(dragOnContent ? panResponder.panHandlers : {})}
            style={[
              styles.container,
              { height: animatedHeight, paddingBottom: keyboardPadding },
              mainContainer,
            ]}
          >
            {/* Indicator */}
            {props.showIndicator && (
              <Animated.View
                style={{
                  alignItems: "center",
                  justifyContent: "center",
                  height: verticalScale(25),
                  opacity: indicatorOpacity,
                }}
              >
                {dragDirection === "up" && <ChevronUpArrow />}
                {dragDirection === "down" && <ChevronDownArrow />}
                {dragDirection === null && (
                  <View
                    style={{
                      width: verticalScale(25),
                      borderRadius: verticalScale(30),
                      height: verticalScale(3.5),
                      backgroundColor: "#4C4C4C",
                    }}
                  />
                )}
              </Animated.View>
            )}

            <View
              pointerEvents={isSnapping ? "none" : "auto"}
              style={{ flex: 1 }}
            >
              {children}
            </View>
          </Animated.View>
        </View>
      </Modal>
    ) : modalVisible ? (
      <View
        pointerEvents="box-none"
        style={[StyleSheet.absoluteFill, styles.wrapper, wrapperColors]}
      >
        {/* Optional dim mask */}
        {!enableTouchThrough && (
          <TouchableOpacity
            style={styles.mask}
            activeOpacity={1}
            onPress={closeOnPressMask ? () => setVisible(false) : undefined}
          />
        )}
        {/* {!enableTouchThrough && closeOnPressMask && (
          <TouchableOpacity
            style={styles.mask}
            activeOpacity={1}
            onPress={() => setVisible(false)}
          />
        )} */}

        {/* Bottom Sheet */}
        <Animated.View
          {...(dragOnContent ? panResponder.panHandlers : {})}
          style={[
            styles.container,
            {
              height: animatedHeight,
              paddingBottom: keyboardPadding,
              position: "absolute",
              bottom: 0,
            },
            mainContainer,
          ]}
        >
          {/* Indicator */}

          {props.showIndicator && (
            <Animated.View
              style={{
                alignItems: "center",
                justifyContent: "center",
                height: verticalScale(25),
                opacity: indicatorOpacity,
              }}
            >
              {dragDirection === "up" && <ChevronUpArrow />}
              {dragDirection === "down" && <ChevronDownArrow />}
              {dragDirection === null && (
                <View
                  style={{
                    width: verticalScale(25),
                    borderRadius: verticalScale(30),
                    height: verticalScale(3.5),
                    backgroundColor: "#4C4C4C",
                  }}
                />
              )}
            </Animated.View>
          )}
          <View
            pointerEvents={isSnapping ? "none" : "auto"}
            style={{ flex: 1 }}
          >
            {children}
          </View>
        </Animated.View>
      </View>
    ) : null;
  },
);

BottomSheet.displayName = "BottomSheet";

const styles = StyleSheet.create({
  wrapper: { flex: 1, backgroundColor: "#00000077" },
  mask: { flex: 1, backgroundColor: "transparent" },
  container: {
    backgroundColor: "#fff",
    width: "100%",
    height: 0,
    overflow: "hidden",
    borderTopRightRadius: 30,
    borderTopLeftRadius: 30,
  },
});

export default memo(BottomSheet);
