// Used in: (tabs)/index.tsx, (tabs)/mylist.tsx
// Full swipeable event card — shows user image, category tiled background, or plain placeholder.
// Handles join / leave / edit / delete actions with animated feedback.

import React, { useState, useEffect } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, ImageSourcePropType } from 'react-native';
import { supabase } from '../lib/supabase/client';
import { LinearGradient } from 'expo-linear-gradient';
import { Ionicons } from '@expo/vector-icons';
import * as Haptics from 'expo-haptics';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
  withSequence,
  withSpring,
  Easing,
} from 'react-native-reanimated';

const CATEGORY_IMAGES: Record<string, ImageSourcePropType> = {
  sports: require('../../assets/images/sports.jpg'),
  party: require('../../assets/images/party.jpg'),
  food: require('../../assets/images/food.jpg'),
  study: require('../../assets/images/study.jpg'),
  ride: require('../../assets/images/ride.jpg'),
  zen: require('../../assets/images/zen.jpg'),
  networking: require('../../assets/images/study.jpg'),
  outdoors: require('../../assets/images/sports.jpg'),
  other: require('../../assets/images/party.jpg'),
};

function getCategoryImage(category?: string): ImageSourcePropType | null {
  if (!category) return null;
  return CATEGORY_IMAGES[category.trim().toLowerCase()] ?? null;
}

const TILE_SIZE = 130;
const COLS = 4;
const ROWS = 5;
// Minimum horizontal distance before a swipe is committed as join/skip
const SWIPE_THRESHOLD = 100;

function TiledBackground({ source }: { source: ImageSourcePropType }) {
  return (
    <View style={StyleSheet.absoluteFill}>
      {Array.from({ length: ROWS }).map((_, row) =>
        Array.from({ length: COLS }).map((_, col) => (
          <Image
            key={`${row}-${col}`}
            source={source}
            style={{
              position: 'absolute',
              top: row * TILE_SIZE,
              left: col * TILE_SIZE,
              width: TILE_SIZE,
              height: TILE_SIZE,
            }}
            resizeMode="cover"
          />
        ))
      )}
    </View>
  );
}

interface Event {
  id: string;
  name: string;
  date_time: string;
  address: string;
  number_of_guests?: number;
  attendee_count?: number;
  profile_id?: string;
  category?: string;
  first_image_url?: string | null;
}

interface Props {
  event: Event;
  onPress?: (event: Event) => void;
  onDelete?: () => void;
  onJoin?: () => void;
  onLeave?: () => void;
  onEdit?: (event: Event) => void;
  onSkip?: () => void;
  distanceLabel?: string;
  swipeable?: boolean;
  slideDirection?: 'left' | 'right';
}

function formatEventDate(value: string): string {
  const d = new Date(value);
  if (Number.isNaN(d.getTime())) return value;
  return d.toLocaleString([], {
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

export default function EventCard({
  event, onPress, onDelete, onJoin, onLeave, onEdit, onSkip,
  distanceLabel, swipeable = false, slideDirection = 'right',
}: Props) {
  const [isJoined, setIsJoined] = useState(false);
  const [isOwner, setIsOwner] = useState(false);
  const [loading, setLoading] = useState(false);

  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);
  const opacity = useSharedValue(1);
  const scale = useSharedValue(1);
  const swipeX = useSharedValue(0);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value + swipeX.value },
      { translateY: translateY.value },
      { scale: scale.value },
    ],
    opacity: opacity.value,
  }));

  // Fade in the "JOIN" indicator as the card is swiped right past 20px
  const joinIndicatorStyle = useAnimatedStyle(() => ({
    opacity: swipeX.value > 20 ? Math.min((swipeX.value - 20) / 60, 1) : 0,
  }));

  // Fade in the "SKIP" indicator as the card is swiped left past 20px
  const skipIndicatorStyle = useAnimatedStyle(() => ({
    opacity: swipeX.value < -20 ? Math.min((-swipeX.value - 20) / 60, 1) : 0,
  }));

  useEffect(() => {
    checkUserStatus();
  }, [event.id]);

  async function checkUserStatus() {
    const user = (await supabase.auth.getUser()).data.user;
    if (!user) return;
    setIsOwner(event.profile_id === user.id);
    const { data } = await supabase
      .from('event_attendees')
      .select('id')
      .eq('event_id', event.id)
      .eq('user_id', user.id)
      .maybeSingle();
    setIsJoined(!!data);
  }

  function animateSendToList(callback: () => void) {
    const direction = slideDirection === 'left' ? -420 : 420;
    const duration = 220;
    scale.value = withSequence(
      withTiming(1.04, { duration: 80, easing: Easing.out(Easing.ease) }),
      withTiming(0.96, { duration: 60 })
    );
    translateX.value = withTiming(direction, { duration, easing: Easing.in(Easing.ease) });
    translateY.value = withTiming(120, { duration });
    opacity.value = withTiming(0, { duration });
    setTimeout(callback, duration + 20);
  }

  async function executeJoin() {
    const user = (await supabase.auth.getUser()).data.user;
    if (!user) return;
    const { error } = await supabase.from('event_attendees').insert({
      event_id: event.id,
      user_id: user.id,
    });
    if (!error) {
      setIsJoined(true);
      onJoin?.();
    }
  }

  const panGesture = Gesture.Pan()
    .runOnJS(true)
    .activeOffsetX([-10, 10])
    .failOffsetY([-10, 10])
    .onUpdate((e) => {
      swipeX.value = e.translationX;
    })
    .onEnd((e) => {
      if (!isOwner && !isJoined && e.translationX > SWIPE_THRESHOLD) {
        Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
        swipeX.value = withTiming(500, { duration: 200 });
        opacity.value = withTiming(0, { duration: 200 });
        setTimeout(executeJoin, 50);
      } else if (e.translationX < -SWIPE_THRESHOLD) {
        Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
        swipeX.value = withTiming(-500, { duration: 200 });
        opacity.value = withTiming(0, { duration: 200 });
        setTimeout(() => onSkip?.(), 220);
      } else {
        swipeX.value = withSpring(0);
      }
    });

  const handleJoin = async () => {
    if (loading) return;
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
    setLoading(true);

    const user = (await supabase.auth.getUser()).data.user;
    if (!user) {
      Alert.alert('Not signed in', 'You must be logged in to join an event.');
      setLoading(false);
      return;
    }

    if (isJoined) {
      setLoading(false);
      Alert.alert('Leave Event', 'Are you sure you want to leave this event?', [
        { text: 'Cancel', style: 'cancel' },
        {
          text: 'Leave',
          style: 'destructive',
          onPress: async () => {
            Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
            const { error } = await supabase
              .from('event_attendees')
              .delete()
              .eq('event_id', event.id)
              .eq('user_id', user.id);
            if (error) {
              Alert.alert('Error', 'Could not leave event. Please try again.');
            } else {
              setIsJoined(false);
              if (onLeave) animateSendToList(onLeave);
            }
          },
        },
      ]);
      return;
    } else {
      const { error } = await supabase.from('event_attendees').insert({
        event_id: event.id,
        user_id: user.id,
      });
      if (error) {
        Alert.alert('Error', 'Could not join event. Please try again.');
      } else {
        setIsJoined(true);
        if (onJoin) animateSendToList(onJoin);
      }
    }
    setLoading(false);
  };

  const handleDelete = () => {
    Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
    Alert.alert('Delete Event', 'This will permanently delete the event for everyone.', [
      { text: 'Cancel', style: 'cancel' },
      {
        text: 'Delete',
        style: 'destructive',
        onPress: async () => {
          const { error } = await supabase.from('event').delete().eq('id', event.id);
          if (error) {
            Alert.alert('Error', 'Could not delete event. Please try again.');
          } else {
            if (onDelete) animateSendToList(onDelete);
          }
        },
      },
    ]);
  };

  const [userImageFailed, setUserImageFailed] = useState(false);
  const userImage = event.first_image_url && !userImageFailed ? { uri: event.first_image_url } : null;
  const categoryImage = getCategoryImage(event.category);

  function renderActions() {
    if (isOwner) {
      return (
        <View style={styles.ownerButtonRow}>
          <TouchableOpacity
            onPress={() => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); onEdit?.(event); }}
            style={[styles.actionButton, styles.editButton, { flex: 1 }]}
          >
            <Text style={styles.actionText}>Edit</Text>
          </TouchableOpacity>
          <TouchableOpacity onPress={handleDelete} style={[styles.actionButton, styles.deleteButton, { flex: 1 }]}>
            <Text style={styles.actionText}>Delete</Text>
          </TouchableOpacity>
        </View>
      );
    }
    return (
      <TouchableOpacity onPress={handleJoin} style={[styles.actionButton, isJoined ? styles.leaveButton : styles.joinButton]}>
        <Text style={styles.actionText}>{loading ? '...' : isJoined ? 'Leave' : 'Join'}</Text>
      </TouchableOpacity>
    );
  }

  const cardInner = (
    <Animated.View style={animatedStyle}>
      {swipeable && (
        <>
          <Animated.View style={[styles.swipeIndicator, styles.joinIndicator, joinIndicatorStyle]}>
            <Ionicons name="checkmark-circle" size={48} color="#22c55e" />
            <Text style={[styles.swipeLabel, { color: '#22c55e' }]}>JOIN</Text>
          </Animated.View>
          <Animated.View style={[styles.swipeIndicator, styles.skipIndicator, skipIndicatorStyle]}>
            <Ionicons name="close-circle" size={48} color="#9ca3af" />
            <Text style={[styles.swipeLabel, { color: '#9ca3af' }]}>SKIP</Text>
          </Animated.View>
        </>
      )}
      <TouchableOpacity onPress={() => onPress?.(event)} activeOpacity={0.9} style={styles.card}>
        {userImage ? (
          <View style={styles.imageCard}>
            <Image source={userImage} style={styles.bgImage} resizeMode="cover" onError={() => setUserImageFailed(true)} />
            <LinearGradient
              colors={['transparent', 'rgba(0,0,0,0.55)', 'rgba(0,0,0,0.92)']}
              locations={[0.3, 0.65, 1]}
              style={styles.overlay}
            />
            <View style={styles.textContent}>
              <Text style={styles.title}>{event.name}</Text>
              <View style={styles.infoContainer}>
                <View style={styles.row}>
                  <Ionicons name="calendar-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{event.date_time ? formatEventDate(event.date_time) : 'No date'}</Text>
                </View>
                <View style={styles.row}>
                  <Ionicons name="location-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{distanceLabel ?? event.address ?? 'No address'}</Text>
                </View>
                <View style={styles.row}>
                  <Ionicons name="people-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{event.attendee_count ?? 0} / {event.number_of_guests ?? 0} going</Text>
                </View>
              </View>
              {renderActions()}
            </View>
          </View>
        ) : categoryImage ? (
          <View style={styles.imageCard}>
            <TiledBackground source={categoryImage} />
            <LinearGradient
              colors={['rgba(0,0,0,0.05)', 'rgba(0,0,0,0.3)', 'rgba(0,0,0,0.75)']}
              locations={[0, 0.5, 1]}
              style={styles.overlay}
            />
            <View style={styles.textContent}>
              <Text style={styles.title}>{event.name}</Text>
              <View style={styles.infoContainer}>
                <View style={styles.row}>
                  <Ionicons name="calendar-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{event.date_time ? formatEventDate(event.date_time) : 'No date'}</Text>
                </View>
                <View style={styles.row}>
                  <Ionicons name="location-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{distanceLabel ?? event.address ?? 'No address'}</Text>
                </View>
                <View style={styles.row}>
                  <Ionicons name="people-outline" size={13} color="rgba(255,255,255,0.85)" style={styles.icon} />
                  <Text style={styles.detail}>{event.attendee_count ?? 0} / {event.number_of_guests ?? 0} going</Text>
                </View>
              </View>
              {renderActions()}
            </View>
          </View>
        ) : (
          <View style={styles.placeholderCard}>
            <Text style={styles.title}>{event.name}</Text>
            <View style={styles.infoContainer}>
              <View style={styles.row}>
                <Ionicons name="calendar-outline" size={13} color="#7878A0" style={styles.icon} />
                <Text style={styles.detail}>{event.date_time ? formatEventDate(event.date_time) : 'No date'}</Text>
              </View>
              <View style={styles.row}>
                <Ionicons name="location-outline" size={13} color="#7878A0" style={styles.icon} />
                <Text style={styles.detail}>{distanceLabel ?? event.address ?? 'No address'}</Text>
              </View>
              <View style={styles.row}>
                <Ionicons name="people-outline" size={13} color="#7878A0" style={styles.icon} />
                <Text style={styles.detail}>{event.attendee_count ?? 0} / {event.number_of_guests ?? 0} going</Text>
              </View>
            </View>
            {renderActions()}
          </View>
        )}
      </TouchableOpacity>
    </Animated.View>
  );

  if (swipeable) {
    return <GestureDetector gesture={panGesture}>{cardInner}</GestureDetector>;
  }
  return cardInner;
}

const styles = StyleSheet.create({
  card: {
    backgroundColor: 'transparent',
    paddingHorizontal: 0,
    paddingVertical: 0,
    borderRadius: 0,
    marginBottom: 24,
  },
  imageCard: {
    width: '100%',
    aspectRatio: 4 / 5,
    overflow: 'hidden',
    justifyContent: 'flex-end',
  },
  bgImage: {
    position: 'absolute',
    top: 0, left: 0, right: 0, bottom: 0,
    width: '100%', height: '100%',
  },
  overlay: {
    position: 'absolute',
    top: 0, left: 0, right: 0, bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.25)',
  },
  placeholderCard: {
    width: '100%',
    backgroundColor: '#1E1E28',
    paddingHorizontal: 14,
    paddingVertical: 18,
    marginBottom: 0,
  },
  actionButton: {
    marginTop: 14,
    paddingVertical: 13,
    borderRadius: 12,
    alignItems: 'center',
  },
  joinButton: { backgroundColor: '#FF6B00' },
  leaveButton: { backgroundColor: '#EF4444' },
  deleteButton: { backgroundColor: '#EF4444' },
  editButton: { backgroundColor: '#7C3AED' },
  ownerButtonRow: {
    flexDirection: 'row',
    gap: 8,
    marginTop: 14,
  },
  actionText: {
    color: '#FFFFFF',
    fontWeight: '700',
  },
  textContent: {
    paddingHorizontal: 16,
    paddingTop: 14,
    paddingBottom: 16,
  },
  title: {
    fontSize: 22,
    fontWeight: '900',
    color: '#FFFFFF',
    marginBottom: 8,
    textShadowColor: 'rgba(0,0,0,0.9)',
    textShadowOffset: { width: 0, height: 2 },
    textShadowRadius: 6,
  },
  infoContainer: {
    gap: 5,
    marginBottom: 4,
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  icon: { marginRight: 6 },
  detail: {
    fontSize: 13,
    color: '#FFFFFF',
    flexShrink: 1,
    fontWeight: '600',
    textShadowColor: 'rgba(0,0,0,0.9)',
    textShadowOffset: { width: 0, height: 1 },
    textShadowRadius: 4,
  },
  swipeIndicator: {
    position: 'absolute',
    top: 0, bottom: 24,
    width: 90,
    justifyContent: 'center',
    alignItems: 'center',
    zIndex: 10,
    gap: 6,
  },
  joinIndicator: {
    right: 20,
  },
  skipIndicator: {
    left: 20,
  },
  swipeLabel: {
    fontSize: 14,
    fontWeight: '900',
    letterSpacing: 1,
  },
});
