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

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(null);

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

    const { mutateAsync: fetchAndSaveGoogleEvents } = useFetchAndSaveGoogleEvents();
    const { mutateAsync: fetchAndSaveOutlookEvents } = useFetchAndSaveOutlookEvents();
    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)) {
            try {
                const googleEvents = Object.entries(profileData?.googleAccounts || {}).map(([email, { accessToken }]) =>
                    fetchAndSaveGoogleEvents({ token: accessToken, email, date: selectedDate })
                );

                const outlookEvents = Object.entries(profileData?.microsoftAccounts || {}).map(([email, token]) =>
                    fetchAndSaveOutlookEvents({ token, email, date: selectedDate })
                );

                const appleEvents = Object.entries(profileData?.appleAccounts || {}).map(([email, token]) =>
                    fetchAndSaveAppleEvents({ token, email, date: selectedDate })
                );

                await Promise.all([...googleEvents, ...outlookEvents, ...appleEvents]);

                setLastSyncDate(selectedDate);
                setLowerBoundDate(newLowerBound);
                setUpperBoundDate(newUpperBound);
                syncedRanges.add(rangeKey);
            } catch (err) {
                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,
    };
};