import React, {useCallback, useEffect, useMemo, useState} from "react";
import {Calendar} from "react-native-big-calendar";
import {ActivityIndicator, StyleSheet, TouchableOpacity, View, ViewStyle} from "react-native";
import {useGetEvents} from "@/hooks/firebase/useGetEvents";
import {useAtom, useSetAtom} from "jotai";
import {
    editVisibleAtom,
    eventForEditAtom,
    isAllDayAtom,
    isFamilyViewAtom,
    modeAtom,
    selectedDateAtom,
    selectedNewEventDateAtom,
} from "@/components/pages/calendar/atoms";
import {useAuthContext} from "@/contexts/AuthContext";
import {CalendarEvent} from "@/components/pages/calendar/interfaces";
import {Text} from "react-native-ui-lib";
import {addDays, compareAsc, format, isWithinInterval, subDays} from "date-fns";
import {useCalSync} from "@/hooks/useCalSync";
import {useSyncEvents} from "@/hooks/useSyncOnScroll";
import {colorMap} from "@/constants/colorMap";
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
import CachedImage from "expo-cached-image";

interface EventCalendarProps {
    calendarHeight: number;
    // WAS USED FOR SCROLLABLE CALENDARS, PERFORMANCE WAS NOT OPTIMAL
    calendarWidth: number;
}

const getTotalMinutes = () => {
    const date = new Date();
    return Math.abs(date.getUTCHours() * 60 + date.getUTCMinutes() - 200);
};


const processEventsForSideBySide = (events: CalendarEvent[]) => {
    if (!events) return [];

    // Group events by day and time slot
    const timeSlots: { [key: string]: CalendarEvent[] } = {};

    events.forEach(event => {
        const startDate = new Date(event.start);
        const endDate = new Date(event.end);

        // If it's an all-day event, mark it and add it directly
        if (event.allDay) {
            const key = `${startDate.toISOString().split('T')[0]}-allday`;
            if (!timeSlots[key]) timeSlots[key] = [];
            timeSlots[key].push({
                ...event,
                isAllDayEvent: true,
                width: 1,
                xPos: 0
            });
            return;
        }

        // Handle multi-day events
        if (startDate.toDateString() !== endDate.toDateString()) {
            // Create array of dates between start and end
            const dates = [];
            let currentDate = new Date(startDate);

            while (currentDate <= endDate) {
                dates.push(new Date(currentDate));
                currentDate.setDate(currentDate.getDate() + 1);
            }

            // Create segments for each day
            dates.forEach((date, index) => {
                const isFirstDay = index === 0;
                const isLastDay = index === dates.length - 1;

                let segmentStart, segmentEnd;

                if (isFirstDay) {
                    // First day: use original start time to end of day
                    segmentStart = new Date(startDate);
                    segmentEnd = new Date(date);
                    segmentEnd.setHours(23, 59, 59);
                } else if (isLastDay) {
                    // Last day: use start of day to original end time
                    segmentStart = new Date(date);
                    segmentStart.setHours(0, 0, 0);
                    segmentEnd = new Date(endDate);
                } else {
                    // Middle days: full day
                    segmentStart = new Date(date);
                    segmentStart.setHours(0, 0, 0);
                    segmentEnd = new Date(date);
                    segmentEnd.setHours(23, 59, 59);
                }

                const key = `${segmentStart.toISOString().split('T')[0]}-${segmentStart.getHours()}`;
                if (!timeSlots[key]) timeSlots[key] = [];

                timeSlots[key].push({
                    ...event,
                    start: segmentStart,
                    end: segmentEnd,
                    isMultiDaySegment: true,
                    isFirstDay,
                    isLastDay,
                    originalStart: startDate,
                    originalEnd: endDate,
                    allDay: true  // Mark multi-day events as all-day events
                });
            });
        } else {
            // Regular event
            const key = `${startDate.toISOString().split('T')[0]}-${startDate.getHours()}`;
            if (!timeSlots[key]) timeSlots[key] = [];
            timeSlots[key].push(event);
        }
    });

    // Process all time slots
    return Object.values(timeSlots).flatMap(slotEvents => {
        // Sort events by start time
        slotEvents.sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime());

        // Find overlapping events (only for non-all-day events)
        return slotEvents.map((event, index) => {
            // If it's an all-day or multi-day event, return as is
            if (event.allDay || event.isMultiDaySegment) {
                return {
                    ...event,
                    width: 1,
                    xPos: 0
                };
            }

            // Handle regular events
            const overlappingEvents = slotEvents.filter((otherEvent, otherIndex) => {
                if (index === otherIndex || otherEvent.allDay || otherEvent.isMultiDaySegment) return false;
                const eventStart = new Date(event.start);
                const eventEnd = new Date(event.end);
                const otherStart = new Date(otherEvent.start);
                const otherEnd = new Date(otherEvent.end);
                return (eventStart < otherEnd && eventEnd > otherStart);
            });

            const total = overlappingEvents.length + 1;
            const position = index % total;

            return {
                ...event,
                width: 1 / total,
                xPos: position / total
            };
        });
    });
};

const renderEvent = (event: CalendarEvent & {
    width: number;
    xPos: number;
    isMultiDaySegment?: boolean;
    isFirstDay?: boolean;
    isLastDay?: boolean;
    originalStart?: Date;
    originalEnd?: Date;
    isAllDayEvent?: boolean;
    allDay?: boolean;
    eventColor?: string;
    attendees?: string[];
    creatorId?: string;
    pfp?: string;
    firstName?: string;
    lastName?: string;
    notes?: string;
    hideHours?: boolean;
}, props: any) => {
    const {data: familyMembers} = useGetFamilyMembers();

    const attendees = useMemo(() => {
        if (!familyMembers || !event.attendees) return event?.creatorId ? [event?.creatorId] : [];
        return familyMembers.filter(member => event?.attendees?.includes(member?.uid!));
    }, [familyMembers, event.attendees]);

    if (event.allDay && !!event.isMultiDaySegment) {
        return (
            <TouchableOpacity
                {...props}
                style={[
                    props.style,
                    {
                        width: '100%',
                        flexDirection: 'row',
                        alignItems: 'center'
                    }
                ]}
            >
                <Text style={styles.allDayEventText} numberOfLines={1}>
                    {event.title}
                    {event.isMultiDaySegment &&
                        ` (${format(new Date(event.start), 'MMM d')} - ${format(new Date(event.end), 'MMM d')})`
                    }
                </Text>
            </TouchableOpacity>
        );
    }

    const originalStyle = Array.isArray(props.style) ? props.style[0] : props.style;

    console.log('Rendering event:', {
        title: event.title,
        start: event.start,
        end: event.end,
        width: event.width,
        xPos: event.xPos,
        isMultiDaySegment: event.isMultiDaySegment
    });


    // Ensure we have Date objects
    const startDate = event.start instanceof Date ? event.start : new Date(event.start);
    const endDate = event.end instanceof Date ? event.end : new Date(event.end);

    const hourHeight = props.hourHeight || 60;
    const startHour = startDate.getHours();
    const startMinutes = startDate.getMinutes();
    const topPosition = (startHour + startMinutes / 60) * hourHeight;

    const endHour = endDate.getHours();
    const endMinutes = endDate.getMinutes();
    const duration = (endHour + endMinutes / 60) - (startHour + startMinutes / 60);
    const height = duration * hourHeight;

    const formatTime = (date: Date) => {
        const hours = date.getHours();
        const minutes = date.getMinutes();
        const ampm = hours >= 12 ? 'pm' : 'am';
        const formattedHours = hours % 12 || 12;
        const formattedMinutes = minutes.toString().padStart(2, '0');
        return `${formattedHours}:${formattedMinutes}${ampm}`;
    };

    const timeString = event.isMultiDaySegment
        ? event.isFirstDay
            ? `${formatTime(startDate)} → 12:00PM`
            : event.isLastDay
                ? `12:00am → ${formatTime(endDate)}`
                : 'All day'
        : `${formatTime(startDate)} - ${formatTime(endDate)}`;

    return (
        <TouchableOpacity
            {...props}
            style={[
                originalStyle,
                {
                    position: 'absolute',
                    width: `${event.width * 100}%`,
                    left: `${event.xPos * 100}%`,
                    top: topPosition,
                    height: height,
                    zIndex: event.isMultiDaySegment ? 1 : 2,
                    shadowRadius: 2,
                    overflow: "hidden"
                }
            ]}
        >
            <View
                style={{
                    flex: 1,
                    backgroundColor: event.eventColor,
                    borderRadius: 4,
                    padding: 8,
                    justifyContent: 'space-between'
                }}
            >
                <View>
                    <Text
                        style={{
                            color: 'white',
                            fontSize: 12,
                            fontFamily: "PlusJakartaSans_500Medium",
                            fontWeight: '600',
                            marginBottom: 4
                        }}
                        numberOfLines={1}
                    >
                        {event.title}
                    </Text>
                    <Text
                        style={{
                            color: 'white',
                            fontSize: 10,
                            fontFamily: "PlusJakartaSans_500Medium",
                            opacity: 0.8
                        }}
                    >
                        {timeString}
                    </Text>
                </View>

                {/* Attendees Section */}
                {attendees?.length > 0 && (
                    <View style={{flexDirection: 'row', marginTop: 8, height: 27.32}}>
                        {attendees?.filter(x=>x?.firstName).slice(0, 5).map((attendee, index) => (
                            <View
                                key={attendee?.uid}
                                style={{
                                    position: 'absolute',
                                    left: index * 19,
                                    width: 20,
                                    height: 20,
                                    borderRadius: 50,
                                    borderWidth: 2,
                                    borderColor: '#f2f2f2',
                                    overflow: 'hidden',
                                    backgroundColor: attendee.eventColor || colorMap.pink,
                                }}
                            >
                                {attendee.pfp ? (
                                    <CachedImage
                                        source={{uri: attendee.pfp}}
                                        style={{width: '100%', height: '100%'}}
                                        cacheKey={attendee.pfp}
                                    />
                                ) : (
                                    <View style={{
                                        flex: 1,
                                        justifyContent: 'center',
                                        alignItems: 'center'
                                    }}>
                                        <Text style={{
                                            color: 'white',
                                            fontSize: 12,
                                            fontFamily: "Manrope_600SemiBold",
                                        }}>
                                            {attendee?.firstName?.at(0)}
                                            {attendee?.lastName?.at(0)}
                                        </Text>
                                    </View>
                                )}
                            </View>
                        ))}
                        {attendees.length > 3 && (
                            <View style={{
                                position: 'absolute',
                                left: 3 * 19,
                                width: 27.32,
                                height: 27.32,
                                borderRadius: 50,
                                borderWidth: 2,
                                borderColor: '#f2f2f2',
                                backgroundColor: colorMap.pink,
                                justifyContent: 'center',
                                alignItems: 'center'
                            }}>
                                <Text style={{
                                    color: 'white',
                                    fontFamily: "Manrope_600SemiBold",
                                    fontSize: 12,
                                }}>
                                    +{attendees.length - 3}
                                </Text>
                            </View>
                        )}
                    </View>
                )}
            </View>
        </TouchableOpacity>
    );
};


export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
    ({calendarHeight}) => {
        const {data: events, isLoading} = useGetEvents();
        const {profileData, user} = useAuthContext();
        const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
        const [mode, setMode] = useAtom(modeAtom);
        const [isFamilyView] = useAtom(isFamilyViewAtom);

        const setEditVisible = useSetAtom(editVisibleAtom);
        const [isAllDay, setIsAllDay] = useAtom(isAllDayAtom);
        const setEventForEdit = useSetAtom(eventForEditAtom);
        const setSelectedNewEndDate = useSetAtom(selectedNewEventDateAtom);

        const {isSyncing} = useSyncEvents()
        const [offsetMinutes, setOffsetMinutes] = useState(getTotalMinutes());
        useCalSync()

        const todaysDate = new Date();

        const handlePressEvent = useCallback(
            (event: CalendarEvent) => {
                if (mode === "day" || mode === "week" || mode === "3days") {
                    setEditVisible(true);
                    setEventForEdit(event);
                } else {
                    setMode("day");
                    setSelectedDate(event.start);
                }
            },
            [setEditVisible, setEventForEdit, mode]
        );

        const handlePressCell = useCallback(
            (date: Date) => {
                if (mode === "day" || mode === "week" || mode === "3days") {
                    setSelectedNewEndDate(date);
                } else {
                    setMode("day");
                    setSelectedDate(date);
                }
            },
            [mode, setSelectedNewEndDate, setSelectedDate]
        );

        const handlePressDayHeader = useCallback(
            (date: Date) => {
                if (mode === "day") {
                    setIsAllDay(true);
                    setSelectedNewEndDate(date);
                    setEditVisible(true);
                }
                if (mode === 'week' || mode === '3days') {
                    setSelectedDate(date)
                    setMode("day")
                }
            },
            [mode, setSelectedNewEndDate]
        );

        const handleSwipeEnd = useCallback(
            (date: Date) => {
                setSelectedDate(date);
            },
            [setSelectedDate]
        );

        const memoizedEventCellStyle = useCallback(
            (event: CalendarEvent) => {
                let eventColor = event.eventColor;
                if (!isFamilyView && (event.attendees?.includes(user?.uid!) || event.creatorId! === user?.uid)) {
                    eventColor = profileData?.eventColor ?? colorMap.teal;
                }

                return {backgroundColor: eventColor, fontSize: 14}
            },
            []
        );

        const memoizedWeekStartsOn = useMemo(
            () => (profileData?.firstDayOfWeek === "Mondays" ? 1 : 0),
            [profileData]
        );

        const isSameDate = useCallback((date1: Date, date2: Date) => {
            return (
                date1.getDate() === date2.getDate() &&
                date1.getMonth() === date2.getMonth() &&
                date1.getFullYear() === date2.getFullYear()
            );
        }, []);

        const dayHeaderColor = useMemo(() => {
            return isSameDate(todaysDate, selectedDate) ? "white" : "#4d4d4d";
        }, [selectedDate, mode]);

        const dateStyle = useMemo(() => {
            if (mode === "week" || mode === "3days") return undefined;
            return isSameDate(todaysDate, selectedDate) && mode === "day"
                ? styles.dayHeader
                : styles.otherDayHeader;
        }, [selectedDate, mode]);

        const memoizedHeaderContentStyle = useMemo(() => {
            if (mode === "day") {
                return styles.dayModeHeader;
            } else if (mode === "week" || mode === "3days") {
                return styles.weekModeHeader;
            } else if (mode === "month") {
                return styles.monthModeHeader;
            } else {
                return {};
            }
        }, [mode]);
        const {enrichedEvents, filteredEvents} = useMemo(() => {
            const startTime = Date.now();

            const startOffset = mode === "month" ? 40 : (mode === "week" || mode === "3days") ? 10 : 1;
            const endOffset = mode === "month" ? 40 : (mode === "week" || mode === "3days") ? 10 : 1;

            const filteredEvents =
                events?.filter(
                    (event) =>
                        event.start &&
                        event.end &&
                        isWithinInterval(event.start, {
                            start: subDays(selectedDate, startOffset),
                            end: addDays(selectedDate, endOffset),
                        }) &&
                        isWithinInterval(event.end, {
                            start: subDays(selectedDate, startOffset),
                            end: addDays(selectedDate, endOffset),
                        })
                ) ?? [];

            const enrichedEvents = filteredEvents.reduce((acc, event) => {
                const dateKey = event.start.toISOString().split("T")[0];
                acc[dateKey] = acc[dateKey] || [];
                acc[dateKey].push({
                    ...event,
                    overlapPosition: false,
                    overlapCount: 0,
                });

                acc[dateKey].sort((a: { start: any; }, b: { start: any; }) => compareAsc(a.start, b.start));

                return acc;
            }, {} as Record<string, CalendarEvent[]>);

            const endTime = Date.now();
            // console.log("memoizedEvents computation time:", endTime - startTime, "ms");

            return {enrichedEvents, filteredEvents};
        }, [events, selectedDate, mode]);

        const renderCustomDateForMonth = (date: Date) => {
            const circleStyle = useMemo<ViewStyle>(
                () => ({
                    width: 30,
                    height: 30,
                    justifyContent: "center",
                    alignItems: "center",
                    borderRadius: 15,
                }),
                []
            );

            const defaultStyle = useMemo<ViewStyle>(
                () => ({
                    ...circleStyle,
                }),
                [circleStyle]
            );

            const currentDateStyle = useMemo<ViewStyle>(
                () => ({
                    ...circleStyle,
                    backgroundColor: "#4184f2",
                }),
                [circleStyle]
            );

            const renderDate = useCallback(
                (date: Date) => {
                    const isCurrentDate = isSameDate(todaysDate, date);
                    const appliedStyle = isCurrentDate ? currentDateStyle : defaultStyle;

                    return (
                        <View style={{alignItems: "center"}}>
                            <View style={appliedStyle}>
                                <Text style={{color: isCurrentDate ? "white" : "black"}}>
                                    {date.getDate()}
                                </Text>
                            </View>
                        </View>
                    );
                },
                [todaysDate, currentDateStyle, defaultStyle]
            );

            return renderDate(date);
        };

        const processedEvents = useMemo(() => {
            return processEventsForSideBySide(filteredEvents);
        }, [filteredEvents]);

        useEffect(() => {
            setOffsetMinutes(getTotalMinutes());
        }, [events, mode]);

        if (isLoading) {
            return (
                <View style={styles.loadingContainer}>
                    {isSyncing && <Text>Syncing...</Text>}
                    <ActivityIndicator size="large" color="#0000ff"/>
                </View>
            );
        }

        return (
            <>
                {isSyncing && (
                    <View style={styles.loadingContainer}>
                        {isSyncing && <Text>Syncing...</Text>}
                        <ActivityIndicator size="large" color="#0000ff"/>
                    </View>
                )}
                <Calendar
                    bodyContainerStyle={styles.calHeader}
                    swipeEnabled
                    mode={mode}
                    sortedMonthView
                    events={filteredEvents}
                    // renderEvent={renderEvent}
                    eventCellStyle={memoizedEventCellStyle}
                    allDayEventCellStyle={memoizedEventCellStyle}
                    // enableEnrichedEvents={true}
                    // enrichedEventsByDate={enrichedEvents}
                    onPressEvent={handlePressEvent}
                    weekStartsOn={memoizedWeekStartsOn}
                    height={calendarHeight}
                    activeDate={todaysDate}
                    date={selectedDate}
                    onPressCell={handlePressCell}
                    headerContentStyle={memoizedHeaderContentStyle}
                    onSwipeEnd={handleSwipeEnd}
                    scrollOffsetMinutes={offsetMinutes}
                    theme={{
                        palette: {
                            nowIndicator: profileData?.eventColor || "#fd1575",
                            gray: {
                                "100": "#e8eaed",
                                "200": "#e8eaed",
                                "500": "#b7b7b7",
                                "800": "#919191",
                            },
                        },
                        typography: {
                            fontFamily: "PlusJakartaSans_500Medium",
                            sm: {fontFamily: "Manrope_600SemiBold", fontSize: 8},
                            xl: {
                                fontFamily: "PlusJakartaSans_500Medium",
                                fontSize: 14,
                            },
                            moreLabel: {},
                            xs: {fontSize: 10},
                        },
                    }}
                    dayHeaderStyle={dateStyle}
                    dayHeaderHighlightColor={"white"}
                    showAdjacentMonths
                    headerContainerStyle={mode !== "month" ? {
                        overflow: "hidden",
                    } : {}}
                    hourStyle={styles.hourStyle}
                    onPressDateHeader={handlePressDayHeader}
                    ampm
                    // renderCustomDateForMonth={renderCustomDateForMonth}
                />
                <View style={{backgroundColor: 'white', height: 50, width: '100%'}}/>
            </>

        );
    }
);

const styles = StyleSheet.create({
    segmentslblStyle: {
        fontSize: 12,
        fontFamily: "Manrope_600SemiBold",
    },
    calHeader: {
        borderWidth: 0,
        paddingBottom: 60,
    },
    dayModeHeader: {
        alignSelf: "flex-start",
        justifyContent: "space-between",
        alignContent: "center",
        width: 38,
        right: 42,
        height: 13,
    },
    weekModeHeader: {},
    monthModeHeader: {},
    loadingContainer: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
        position: "absolute",
        width: "100%",
        height: "100%",
        zIndex: 100,
        backgroundColor: "rgba(255, 255, 255, 0.9)",
    },
    dayHeader: {
        backgroundColor: "#4184f2",
        aspectRatio: 1,
        borderRadius: 100,
        alignItems: "center",
        justifyContent: "center",
    },
    otherDayHeader: {
        backgroundColor: "transparent",
        color: "#919191",
        aspectRatio: 1,
        borderRadius: 100,
        alignItems: "center",
        justifyContent: "center",
    },
    hourStyle: {
        color: "#5f6368",
        fontSize: 12,
        fontFamily: "Manrope_500Medium",
    },
    eventCell: {
        flex: 1,
        borderRadius: 4,
        padding: 4,
        height: '100%',
        justifyContent: 'center',
    },
    eventTitle: {
        color: 'white',
        fontSize: 12,
        fontFamily: "PlusJakartaSans_500Medium",
    },
});
