import { useState, useEffect, useCallback } from "react";
import { useAuthContext } from "@/contexts/AuthContext";
import { useAtomValue } from "jotai";
import { useFetchAndSaveGoogleEvents } from "./useFetchAndSaveGoogleEvents";
import { useFetchAndSaveAppleEvents } from "./useFetchAndSaveAppleEvents";
import { useFetchAndSaveMicrosoftEvents } from "./useFetchAndSaveOutlookEvents";
import { selectedDateAtom } from "@/components/pages/calendar/atoms";
import { addDays, subDays, isBefore, isAfter, format } from "date-fns";

interface SyncResponse {
    success: boolean;
    eventCount?: number;
    error?: string;
}

export const useSyncEvents = () => {
    const { profileData } = useAuthContext();
    const selectedDate = useAtomValue(selectedDateAtom);

    const [lastSyncDate, setLastSyncDate] = useState<Date>(selectedDate);
    const [lowerBoundDate, setLowerBoundDate] = useState<Date>(subDays(selectedDate, 6 * 30));
    const [upperBoundDate, setUpperBoundDate] = useState<Date>(addDays(selectedDate, 6 * 30));
    const [isSyncing, setIsSyncing] = useState(false);
    const [error, setError] = useState<Error | null>(null);
    const [syncStats, setSyncStats] = useState<{
        total: number;
        success: number;
        failed: number;
        events: number;
    }>({ total: 0, success: 0, failed: 0, events: 0 });

    const syncedRanges = useState<Set<string>>(new Set())[0];

    const { mutateAsync: fetchAndSaveGoogleEvents } = useFetchAndSaveGoogleEvents();
    const { mutateAsync: fetchAndSaveOutlookEvents } = useFetchAndSaveMicrosoftEvents();
    const { mutateAsync: fetchAndSaveAppleEvents } = useFetchAndSaveAppleEvents();

    const generateRangeKey = (startDate: Date, endDate: Date) => {
        return `${format(startDate, "yyyy-MM-dd")}_${format(endDate, "yyyy-MM-dd")}`;
    };

    const syncEvents = useCallback(async () => {
        setIsSyncing(true);
        setError(null);

        const newLowerBound = subDays(selectedDate, 6 * 30);
        const newUpperBound = addDays(selectedDate, 6 * 30);
        const rangeKey = generateRangeKey(newLowerBound, newUpperBound);

        if (syncedRanges.has(rangeKey)) {
            setIsSyncing(false);
            return;
        }

        if (isBefore(selectedDate, lowerBoundDate) || isAfter(selectedDate, upperBoundDate)) {
            const results: SyncResponse[] = [];
            const stats = { total: 0, success: 0, failed: 0, events: 0 };

            try {
                if (profileData?.googleAccounts) {
                    for (const [email] of Object.entries(profileData.googleAccounts)) {
                        try {
                            stats.total++;
                            const result = await fetchAndSaveGoogleEvents({ email }) as SyncResponse;
                            if (result.success) {
                                stats.success++;
                                stats.events += result.eventCount || 0;
                            } else {
                                stats.failed++;
                            }
                            results.push(result);
                        } catch (err) {
                            stats.failed++;
                            console.error(`Failed to sync Google calendar for ${email}:`, err);
                        }
                    }
                }

                if (profileData?.microsoftAccounts) {
                    for (const [email] of Object.entries(profileData.microsoftAccounts)) {
                        try {
                            stats.total++;
                            const result = await fetchAndSaveOutlookEvents({ email });
                            if (result.success) {
                                stats.success++;
                                stats.events += result.eventCount || 0;
                            } else {
                                stats.failed++;
                            }
                            results.push(result);
                        } catch (err) {
                            stats.failed++;
                            console.error(`Failed to sync Microsoft calendar for ${email}:`, err);
                        }
                    }
                }

                if (profileData?.appleAccounts) {
                    for (const [email] of Object.entries(profileData.appleAccounts)) {
                        try {
                            stats.total++;
                            const result = await fetchAndSaveAppleEvents({ email });
                        } catch (err) {
                            stats.failed++;
                            console.error(`Failed to sync Apple calendar for ${email}:`, err);
                        }
                    }
                }

                setSyncStats(stats);
                setLastSyncDate(selectedDate);
                setLowerBoundDate(newLowerBound);
                setUpperBoundDate(newUpperBound);
                syncedRanges.add(rangeKey);

                if (stats.failed > 0) {
                    throw new Error(`Failed to sync ${stats.failed} calendars`);
                }

            } catch (err: any) {
                console.error("Error syncing events:", err);
                setError(err);
            } finally {
                setIsSyncing(false);
            }
        } else {
            setIsSyncing(false);
        }
    }, [
        selectedDate,
        lowerBoundDate,
        upperBoundDate,
        profileData,
        fetchAndSaveGoogleEvents,
        fetchAndSaveOutlookEvents,
        fetchAndSaveAppleEvents,
        syncedRanges
    ]);

    useEffect(() => {
        syncEvents();
    }, [selectedDate, syncEvents]);

    return {
        isSyncing,
        error,
        lastSyncDate,
        lowerBoundDate,
        upperBoundDate,
        syncStats,
    };
};