import { Ionicons } from "@expo/vector-icons";
import { ReactNode, useRef } from "react";
import { Pressable, type PressableProps, StyleSheet, Text, View } from "react-native";
import Swipeable, {
  type SwipeableMethods,
} from "react-native-gesture-handler/ReanimatedSwipeable";

import { fonts, radii, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import type { ThemeColors } from "@/lib/theme-palette";
import { useThemedStyles } from "@/lib/use-themed-styles";

export type SwipeAction = {
  key: string;
  label: string;
  icon: keyof typeof Ionicons.glyphMap;
  color: string;
  backgroundColor: string;
  onPress: () => void;
};

type SwipeableRowProps = {
  children: ReactNode;
  actions: SwipeAction[];
  enabled?: boolean;
  backgroundColor?: string;
  onPress?: () => void;
  onLongPress?: () => void;
  contentStyle?: PressableProps["style"];
};

export function SwipeableRow({
  children,
  actions,
  enabled = true,
  backgroundColor,
  onPress,
  onLongPress,
  contentStyle,
}: SwipeableRowProps) {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createSwipeableRowStyles);
  const rowBackground = backgroundColor ?? colors.background;
  const swipeRef = useRef<SwipeableMethods>(null);
  const rowOpenRef = useRef(false);
  const suppressPressUntilRef = useRef(0);

  function suppressContentPress() {
    suppressPressUntilRef.current = Date.now() + 350;
  }

  function handleContentPress() {
    if (!onPress) return;

    if (rowOpenRef.current || Date.now() < suppressPressUntilRef.current) {
      swipeRef.current?.close();
      rowOpenRef.current = false;
      return;
    }

    onPress();
  }

  function renderContent() {
    if (!onPress && !onLongPress) {
      return (
        <View
          style={[
            styles.row,
            { backgroundColor: rowBackground },
            typeof contentStyle === "function" ? undefined : contentStyle,
          ]}
        >
          {children}
        </View>
      );
    }

    return (
      <Pressable
        accessibilityRole="button"
        onPress={handleContentPress}
        onLongPress={onLongPress}
        style={(state) => [
          styles.row,
          { backgroundColor: rowBackground },
          typeof contentStyle === "function" ? contentStyle(state) : contentStyle,
        ]}
      >
        {children}
      </Pressable>
    );
  }

  function renderRightActions() {
    return (
      <View style={styles.actions}>
        {actions.map((action) => (
          <Pressable
            key={action.key}
            style={[styles.actionButton, { backgroundColor: action.backgroundColor }]}
            onPress={() => {
              suppressContentPress();
              swipeRef.current?.close();
              rowOpenRef.current = false;
              action.onPress();
            }}
          >
            <Ionicons name={action.icon} size={20} color={action.color} />
            <Text style={[styles.actionLabel, { color: action.color }]}>{action.label}</Text>
          </Pressable>
        ))}
      </View>
    );
  }

  if (!enabled || actions.length === 0) {
    return renderContent();
  }

  return (
    <Swipeable
      ref={swipeRef}
      renderRightActions={renderRightActions}
      overshootRight={false}
      onSwipeableOpenStartDrag={suppressContentPress}
      onSwipeableCloseStartDrag={suppressContentPress}
      onSwipeableWillOpen={() => {
        suppressContentPress();
        rowOpenRef.current = true;
      }}
      onSwipeableWillClose={suppressContentPress}
      onSwipeableClose={() => {
        rowOpenRef.current = false;
      }}
    >
      {renderContent()}
    </Swipeable>
  );
}

const createSwipeableRowStyles = (colors: ThemeColors) =>
  StyleSheet.create({
    row: {
      backgroundColor: colors.background,
      borderRadius: radii.lg,
      overflow: "hidden",
      marginBottom: spacing.xs,
    },
    actions: {
      flexDirection: "row",
      alignItems: "stretch",
    },
    actionButton: {
      width: 80,
      alignItems: "center",
      justifyContent: "center",
      gap: spacing.xs,
      borderRadius: radii.md,
      marginLeft: spacing.xs,
    },
    actionLabel: {
      fontFamily: fonts.bodyMedium,
      fontSize: 11,
    },
  });
