import { useEffect, useState } from "react";
import { LayoutChangeEvent, StyleSheet, Text, View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
  withTiming,
} from "react-native-reanimated";

interface SliderProps {
  min?: number;
  max?: number;
  step?: number;
  range?: boolean;
  value?: number | [number, number];
  onValueChange?: (value: any) => void;
  onSlidingComplete?: (value: any) => void;
  disabled?: boolean;
  trackHeight?: number;
  thumbSize?: number;
  activeColor?: string;
  inactiveColor?: string;
  marks?: Record<number, string>;
  style?: any;
}

export default function Slider({
  min = 0,
  max = 100,
  step = 1,
  range = false,
  value = 0,
  onValueChange,
  onSlidingComplete,
  disabled = false,
  trackHeight = 4,
  thumbSize = 20,
  activeColor = "#1677ff", // Ant Design blue
  inactiveColor = "#e5e7eb", // Gray-200
  marks,
  style,
}: SliderProps) {
  const [width, setWidth] = useState(0);

  // Shared values for positions
  const translateX1 = useSharedValue(0); // Left thumb (or 0 for single)
  const translateX2 = useSharedValue(0); // Right thumb (or value for single)

  const isDragging1 = useSharedValue(false);
  const isDragging2 = useSharedValue(false);
  const scale1 = useSharedValue(1);
  const scale2 = useSharedValue(1);
  const context1 = useSharedValue(0);
  const context2 = useSharedValue(0);

  // Calculate position from value
  const getPositionFromValue = (val: number) => {
    "worklet";
    if (width === 0) return 0;
    const clampedVal = Math.min(Math.max(val, min), max);
    return ((clampedVal - min) / (max - min)) * width;
  };

  // Calculate value from position
  const getValueFromPosition = (pos: number) => {
    "worklet";
    if (width === 0) return min;
    const percentage = Math.min(Math.max(pos, 0), width) / width;
    const rawValue = min + percentage * (max - min);

    // Snap to step
    const steppedValue = Math.round(rawValue / step) * step;
    return Math.min(Math.max(steppedValue, min), max);
  };

  // Update positions when props change
  useEffect(() => {
    if (width === 0) return;

    if (range) {
      const vals = Array.isArray(value) ? value : [min, value as number];
      const v1 = Math.min(vals[0], vals[1]);
      const v2 = Math.max(vals[0], vals[1]);

      if (!isDragging1.value) {
        translateX1.value = withTiming(getPositionFromValue(v1), {
          duration: 200,
        });
      }
      if (!isDragging2.value) {
        translateX2.value = withTiming(getPositionFromValue(v2), {
          duration: 200,
        });
      }
    } else {
      const val = typeof value === "number" ? value : value[0];
      if (!isDragging2.value) {
        translateX2.value = withTiming(getPositionFromValue(val), {
          duration: 200,
        });
      }
      translateX1.value = 0; // Always 0 for single slider track start
    }
  }, [value, width, min, max, range]);

  // Thumb 1 Gesture (Only for range)
  const thumb1Gesture = Gesture.Pan()
    .enabled(!disabled && range)
    .onStart(() => {
      context1.value = translateX1.value;
      isDragging1.value = true;
      scale1.value = withSpring(1.2);
    })
    .onUpdate((event) => {
      if (width === 0) return;
      let newPos = context1.value + event.translationX;
      // Constrain: 0 <= newPos <= translateX2
      const maxPos = translateX2.value;
      newPos = Math.min(Math.max(newPos, 0), maxPos);
      translateX1.value = newPos;

      if (onValueChange) {
        const v1 = getValueFromPosition(newPos);
        const v2 = getValueFromPosition(translateX2.value);
        runOnJS(onValueChange)([v1, v2]);
      }
    })
    .onEnd(() => {
      isDragging1.value = false;
      scale1.value = withSpring(1);
      if (onSlidingComplete) {
        const v1 = getValueFromPosition(translateX1.value);
        const v2 = getValueFromPosition(translateX2.value);
        runOnJS(onSlidingComplete)([v1, v2]);
      }
    });

  // Thumb 2 Gesture (Main thumb for single, Right thumb for range)
  const thumb2Gesture = Gesture.Pan()
    .enabled(!disabled)
    .onStart(() => {
      context2.value = translateX2.value;
      isDragging2.value = true;
      scale2.value = withSpring(1.2);
    })
    .onUpdate((event) => {
      if (width === 0) return;
      let newPos = context2.value + event.translationX;
      // Constrain: translateX1 <= newPos <= width
      const minPos = range ? translateX1.value : 0;
      newPos = Math.min(Math.max(newPos, minPos), width);
      translateX2.value = newPos;

      if (onValueChange) {
        const v2 = getValueFromPosition(newPos);
        if (range) {
          const v1 = getValueFromPosition(translateX1.value);
          runOnJS(onValueChange)([v1, v2]);
        } else {
          runOnJS(onValueChange)(v2);
        }
      }
    })
    .onEnd(() => {
      isDragging2.value = false;
      scale2.value = withSpring(1);
      if (onSlidingComplete) {
        const v2 = getValueFromPosition(translateX2.value);
        if (range) {
          const v1 = getValueFromPosition(translateX1.value);
          runOnJS(onSlidingComplete)([v1, v2]);
        } else {
          runOnJS(onSlidingComplete)(v2);
        }
      }
    });

  const trackStyle = useAnimatedStyle(() => {
    return {
      left: range ? translateX1.value : 0,
      width: range ? translateX2.value - translateX1.value : translateX2.value,
    };
  });

  const thumb1Style = useAnimatedStyle(() => {
    return {
      transform: [
        { translateX: translateX1.value - thumbSize / 2 },
        { scale: scale1.value },
      ],
      zIndex: isDragging1.value ? 10 : 1,
    };
  });

  const thumb2Style = useAnimatedStyle(() => {
    return {
      transform: [
        { translateX: translateX2.value - thumbSize / 2 },
        { scale: scale2.value },
      ],
      zIndex: isDragging2.value ? 10 : 1,
    };
  });

  const onLayout = (event: LayoutChangeEvent) => {
    setWidth(event.nativeEvent.layout.width);
  };

  const containerHeight = Math.max(trackHeight, thumbSize) + (marks ? 30 : 0);
  const marksTop = Math.max(trackHeight, thumbSize) + 10;

  return (
    <View style={[styles.container, style, { height: containerHeight }]}>
      <View
        style={[
          styles.track,
          {
            height: trackHeight,
            backgroundColor: inactiveColor,
            borderRadius: trackHeight / 2,
          },
        ]}
        onLayout={onLayout}
      >
        <Animated.View
          style={[
            styles.activeTrack,
            trackStyle,
            {
              height: trackHeight,
              backgroundColor: activeColor,
              borderRadius: trackHeight / 2,
            },
          ]}
        />
      </View>

      {/* Thumb 1 - Only render if range is true */}
      {range && (
        <GestureDetector gesture={thumb1Gesture}>
          <Animated.View
            style={[
              styles.thumb,
              thumb1Style,
              {
                width: thumbSize,
                height: thumbSize,
                borderRadius: thumbSize / 2,
                backgroundColor: "white",
                borderColor: activeColor,
                borderWidth: 2,
              },
              disabled && styles.disabledThumb,
            ]}
          />
        </GestureDetector>
      )}

      {/* Thumb 2 - Always render */}
      <GestureDetector gesture={thumb2Gesture}>
        <Animated.View
          style={[
            styles.thumb,
            thumb2Style,
            {
              width: thumbSize,
              height: thumbSize,
              borderRadius: thumbSize / 2,
              backgroundColor: "white",
              borderColor: activeColor,
              borderWidth: 2,
            },
            disabled && styles.disabledThumb,
          ]}
        />
      </GestureDetector>

      {/* Marks */}
      {marks && (
        <View
          style={{
            position: "absolute",
            top: marksTop,
            width: "100%",
            height: 20,
          }}
        >
          {Object.entries(marks).map(([key, label]) => {
            const val = Number(key);
            const pos = getPositionFromValue(val);
            const leftPos = Math.max(0, Math.min(pos - 10, width - 40));
            return (
              <Text
                key={key}
                style={{
                  position: "absolute",
                  left: leftPos,
                  fontSize: 12,
                  color: "#666",
                  textAlign: "center",
                  width: "auto",
                  marginTop: 5,
                }}
              >
                {label}
              </Text>
            );
          })}
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
    width: "100%",
  },
  track: {
    width: "100%",
    position: "absolute",
    overflow: "hidden",
  },
  activeTrack: {
    position: "absolute",
    left: 0,
    top: 0,
  },
  thumb: {
    position: "absolute",
    left: 0,
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
    elevation: 5,
  },
  disabledThumb: {
    borderColor: "#ccc",
  },
});
