import React, { useRef, useEffect, useCallback } from "react";
import {
  View,
  Text,
  StyleSheet,
  Modal,
  Animated,
  PanResponder,
  TouchableWithoutFeedback,
  Dimensions,
  ScrollView,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

const { width: SCREEN_WIDTH } = Dimensions.get("window");

type SnapPoint = "sm" | "md" | "lg" | "full";
type Side = "left" | "right";

const SNAP_WIDTHS: Record<SnapPoint, number> = {
  sm: SCREEN_WIDTH * 0.55,
  md: SCREEN_WIDTH * 0.7,
  lg: SCREEN_WIDTH * 0.85,
  full: SCREEN_WIDTH,
};

interface SidebarPanelProps {
  visible: boolean;
  onClose: () => void;
  side?: Side;
  snapPoint?: SnapPoint;
  title?: string;
  subtitle?: string;
  showHandle?: boolean;
  showOverlay?: boolean;
  closeOnOverlayPress?: boolean;
  scrollable?: boolean;
  children: React.ReactNode;
}

export default function SidebarPanel({
  visible,
  onClose,
  side = "left",
  snapPoint = "md",
  title,
  subtitle,
  showHandle = true,
  showOverlay = true,
  closeOnOverlayPress = true,
  scrollable = false,
  children,
}: SidebarPanelProps) {
  const panelWidth = SNAP_WIDTHS[snapPoint];

  // Off-screen starting position: negative for left, positive for right
  const offScreen = side === "left" ? -panelWidth : panelWidth;

  const translateX = useRef(new Animated.Value(offScreen)).current;
  const overlayOpacity = useRef(new Animated.Value(0)).current;
  const lastGestureX = useRef(0);
  // Live refs so panResponder (created once) always reads current values
  const sideRef = useRef(side);
  const closePanelRef = useRef<() => void>(() => {});
  const panelWidthRef = useRef(panelWidth);
  useEffect(() => {
    sideRef.current = side;
  }, [side]);
  useEffect(() => {
    panelWidthRef.current = panelWidth;
  }, [panelWidth]);

  const openPanel = useCallback(() => {
    Animated.parallel([
      Animated.spring(translateX, {
        toValue: 0,
        damping: 20,
        stiffness: 200,
        mass: 0.8,
        useNativeDriver: true,
      }),
      Animated.timing(overlayOpacity, {
        toValue: 1,
        duration: 280,
        useNativeDriver: true,
      }),
    ]).start();
  }, [translateX, overlayOpacity]);

  const closePanel = useCallback(() => {
    Animated.parallel([
      Animated.spring(translateX, {
        toValue: offScreen,
        damping: 20,
        stiffness: 200,
        mass: 0.8,
        useNativeDriver: true,
      }),
      Animated.timing(overlayOpacity, {
        toValue: 0,
        duration: 220,
        useNativeDriver: true,
      }),
    ]).start(() => onClose());
  }, [translateX, overlayOpacity, offScreen, onClose]);

  // Keep the ref up to date after closePanel is (re)created
  useEffect(() => {
    closePanelRef.current = closePanel;
  }, [closePanel]);

  useEffect(() => {
    if (visible) {
      translateX.setValue(offScreen);
      openPanel();
    }
  }, [visible, offScreen, openPanel, translateX]);

  const panResponder = useRef(
    PanResponder.create({
      // Claim the gesture as soon as horizontal movement is detected
      onStartShouldSetPanResponder: () => false,
      onMoveShouldSetPanResponder: (_, { dx, dy }) =>
        Math.abs(dx) > 5 && Math.abs(dx) > Math.abs(dy),
      onPanResponderGrant: () => {
        lastGestureX.current = 0;
      },
      onPanResponderMove: (_, { dx }) => {
        const isDismissDir = sideRef.current === "left" ? dx < 0 : dx > 0;
        // Follow finger when dragging away; rubber-band when pushing in
        translateX.setValue(isDismissDir ? dx : dx * 0.08);
        lastGestureX.current = dx;
      },
      onPanResponderRelease: (_, { dx, vx }) => {
        const currentSide = sideRef.current;
        const width = panelWidthRef.current;
        const isDismissDir = currentSide === "left" ? dx < 0 : dx > 0;
        const movedEnough = Math.abs(dx) > width * 0.25; // 25% to dismiss
        const flicked = currentSide === "left" ? vx < -0.8 : vx > 0.8;

        if (isDismissDir && (movedEnough || flicked)) {
          closePanelRef.current();
        } else {
          Animated.spring(translateX, {
            toValue: 0,
            damping: 18,
            stiffness: 180,
            useNativeDriver: true,
          }).start();
        }
      },
      onPanResponderTerminate: () => {
        // Snap back if gesture is stolen (e.g. scroll view)
        Animated.spring(translateX, {
          toValue: 0,
          damping: 18,
          stiffness: 180,
          useNativeDriver: true,
        }).start();
      },
    }),
  ).current;

  if (!visible) return null;

  const ContentWrapper = scrollable ? ScrollView : View;
  const contentWrapperProps = scrollable
    ? {
        bounces: false,
        showsVerticalScrollIndicator: false,
        contentContainerStyle: styles.scrollContent,
      }
    : { style: styles.content };

  const sheetPositionStyle =
    side === "left"
      ? { left: 0, borderTopRightRadius: 24, borderBottomRightRadius: 24 }
      : { right: 0, borderTopLeftRadius: 24, borderBottomLeftRadius: 24 };

  const shadowStyle =
    side === "left"
      ? { shadowOffset: { width: 6, height: 0 } }
      : { shadowOffset: { width: -6, height: 0 } };

  return (
    <Modal
      transparent
      visible={visible}
      animationType="none"
      statusBarTranslucent
      onRequestClose={closePanel}
    >
      {/* Overlay */}
      {showOverlay && (
        <TouchableWithoutFeedback
          onPress={closeOnOverlayPress ? closePanel : undefined}
        >
          <Animated.View
            style={[
              styles.overlay,
              {
                opacity: overlayOpacity.interpolate({
                  inputRange: [0, 1],
                  outputRange: [0, 0.55],
                }),
              },
            ]}
          />
        </TouchableWithoutFeedback>
      )}

      {/* Panel */}
      <Animated.View
        style={[
          styles.panel,
          sheetPositionStyle,
          shadowStyle,
          { width: panelWidth, transform: [{ translateX }] },
        ]}
        {...panResponder.panHandlers}
      >
        {/* Content */}
        <ContentWrapper {...contentWrapperProps}>
          <SafeAreaView>{children}</SafeAreaView>
        </ContentWrapper>
      </Animated.View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  overlay: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: "#0a0a12",
  },
  panel: {
    position: "absolute",
    top: 0,
    bottom: 0,
    backgroundColor: "#ffffff",
    shadowColor: "#000",
    shadowOpacity: 0.14,
    shadowRadius: 20,
    elevation: 24,
  },
  header: {
    paddingHorizontal: 24,
    paddingBottom: 16,
    borderBottomWidth: 1,
    borderBottomColor: "#F3F4F6",
  },
  content: {
    flex: 1,
    paddingHorizontal: 24,
    paddingTop: 16,
  },
  scrollContent: {
    paddingHorizontal: 24,
    paddingTop: 16,
    paddingBottom: 32,
  },
});
