import { Ionicons } from "@expo/vector-icons";
import type { ComponentProps } from "react";
import { useEffect, useRef, useState } from "react";
import {
  Animated,
  OpaqueColorValue,
  Pressable,
  StyleProp,
  StyleSheet,
  View,
  ViewStyle,
} from "react-native";

const SIZE_PRESETS = {
  sm: { width: 64, height: 32 },
  md: { width: 80, height: 40 },
  lg: { width: 96, height: 48 },
} as const;

type SwitchSize = keyof typeof SIZE_PRESETS;

const DEFAULT_TOGGLE_DURATION = 400;

// Default both backgrounds to a grey tone when not provided
const DEFAULT_INACTIVE_BG = "#D3DAD9";
const DEFAULT_ACTIVE_BG = "#D3DAD9";
const PRESSED_SCALE = 0.96;
const PRESS_FEEDBACK_DURATION = 120;

type IoniconName = ComponentProps<typeof Ionicons>["name"];

type SliceSwitchProps = {
  size?: SwitchSize;
  leftIcon?: IoniconName;
  leftIconColor?: string | OpaqueColorValue | undefined;
  rightIconColor?: string | OpaqueColorValue | undefined;
  rightIcon?: IoniconName;
  duration?: number;
  activeBackgroundColor?: string;
  inactiveBackgroundColor?: string;
  inactiveOverlayColor?: string;
  activeOverlayColor?: string;
  style?: StyleProp<ViewStyle>;
  onChange?: (value: boolean) => void;
  value?: boolean;
};

const SliceSwitch = ({
  size = "md",
  leftIcon,
  rightIcon,
  duration,
  activeBackgroundColor = DEFAULT_ACTIVE_BG,
  inactiveBackgroundColor = DEFAULT_INACTIVE_BG,
  leftIconColor = "#fff",
  rightIconColor = "#fff",
  inactiveOverlayColor = "#000",
  activeOverlayColor = "#000",
  style,
  onChange,
  value,
}: SliceSwitchProps) => {
  const { width: containerWidth, height: containerHeight } =
    SIZE_PRESETS[size] ?? SIZE_PRESETS.md;
  const animationDuration = Math.max(duration ?? DEFAULT_TOGGLE_DURATION, 0);
  const [isOn, setIsOn] = useState(value ?? false);
  const [bgOn, setBgOn] = useState(value ?? false);
  const progress = useRef(new Animated.Value(value ? 1 : 0)).current;
  const pressScale = useRef(new Animated.Value(1)).current;
  const overlayTranslateX = useRef(
    new Animated.Value(value ? containerWidth / 2 : 0)
  ).current;
  const listenerIdRef = useRef<string | number | null>(null);

  // Sync with external value prop if provided
  useEffect(() => {
    if (value !== undefined && value !== isOn) {
      animateToValue(value);
    }
  }, [value]);

  const animateToValue = (next: boolean) => {
    const targetValue = next ? 1 : 0;
    const overlayTarget = next ? containerWidth / 2 : 0;

    progress.stopAnimation();
    overlayTranslateX.stopAnimation();

    if (animationDuration <= 0) {
      progress.setValue(targetValue);
      overlayTranslateX.setValue(overlayTarget);
      setIsOn(next);
      setBgOn(next);
      return;
    }

    setIsOn(next);

    Animated.parallel([
      Animated.timing(progress, {
        toValue: targetValue,
        duration: animationDuration,
        useNativeDriver: true,
      }),
      Animated.timing(overlayTranslateX, {
        toValue: overlayTarget,
        duration: animationDuration,
        useNativeDriver: true,
      }),
    ]).start(() => {
      setBgOn(next);
    });

    // Remove any previous listener
    if (listenerIdRef.current != null) {
      progress.removeListener(listenerIdRef.current as string);
      listenerIdRef.current = null;
    }

    // Swap image & background exactly at 50% progress
    let swapped = false;
    listenerIdRef.current = progress.addListener(({ value }) => {
      if (swapped) return;
      if (next && value >= 0.5) {
        swapped = true;
        setBgOn(next);
        if (listenerIdRef.current != null) {
          progress.removeListener(listenerIdRef.current as string);
          listenerIdRef.current = null;
        }
      }
      if (!next && value <= 0.5) {
        swapped = true;
        setBgOn(next);
        if (listenerIdRef.current != null) {
          progress.removeListener(listenerIdRef.current as string);
          listenerIdRef.current = null;
        }
      }
    });
  };

  const handleToggle = () => {
    const next = !isOn;
    if (value === undefined) {
      animateToValue(next);
    }
    onChange?.(next);
  };

  const handlePressIn = () => {
    pressScale.stopAnimation();
    Animated.timing(pressScale, {
      toValue: PRESSED_SCALE,
      duration: PRESS_FEEDBACK_DURATION,
      useNativeDriver: true,
    }).start();
  };

  const handlePressOut = () => {
    pressScale.stopAnimation();
    Animated.timing(pressScale, {
      toValue: 1,
      duration: PRESS_FEEDBACK_DURATION,
      useNativeDriver: true,
    }).start();
  };

  return (
    <Pressable
      onPress={handleToggle}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      accessibilityRole="switch"
      accessibilityState={{ checked: isOn }}
      style={[styles.pressable, style]}
    >
      <Animated.View
        style={[
          styles.shadowWrapper,
          {
            transform: [{ scale: pressScale }],
            width: containerWidth,
            height: containerHeight,
            borderRadius: containerHeight / 2,
          },
        ]}
      >
        <View
          style={[
            styles.container,
            {
              flexDirection: "row",
              justifyContent: "space-between",
              borderRadius: containerHeight / 2,
              backgroundColor: bgOn
                ? activeBackgroundColor
                : inactiveBackgroundColor,
            },
          ]}
        >
          <Animated.View
            style={{
              position: "absolute",
              width: containerWidth / 2,
              height: containerHeight * 0.95,
              top: containerHeight * 0.01,
              left: 0,
              borderRadius: containerHeight * 0.95 / 2,
              zIndex: 10,
              backgroundColor: bgOn ? activeOverlayColor : inactiveOverlayColor,
              transform: [{ translateX: overlayTranslateX }],
            }}
          />
          <View className="h-full w-1/2 items-center justify-center ">
            <Ionicons
              name={leftIcon ?? "sunny"}
              size={20}
              color={leftIconColor ?? "#fff"}
            />
          </View>
          <View className="h-full  w-1/2 items-center justify-center ">
            <Ionicons
              name={rightIcon ?? "moon"}
              size={20}
              color={rightIconColor ?? "#fff"}
            />
          </View>
        </View>
      </Animated.View>
    </Pressable>
  );
};

const styles = StyleSheet.create({
  pressable: {
    alignSelf: "flex-start",
  },
  shadowWrapper: {
    justifyContent: "center",
    position: "relative",
    shadowColor: "#000",
    shadowOpacity: 0.15,
    shadowOffset: { width: 0, height: 4 },
    shadowRadius: 6,
    elevation: 6,
    backgroundColor: "transparent",
  },
  container: {
    flex: 1,
    justifyContent: "center",
    position: "relative",
    overflow: "hidden",
  },
  knob: {
    position: "absolute",
    top: 0,
    left: 0,
  },
});

export default SliceSwitch;
