import {useAuthContext} from "@/contexts/AuthContext";
import {useEffect} from "react";
import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData";
import {useFetchAndSaveGoogleEvents} from "@/hooks/useFetchAndSaveGoogleEvents";
import {useFetchAndSaveMicrosoftEvents} from "@/hooks/useFetchAndSaveOutlookEvents";
import {useFetchAndSaveAppleEvents} from "@/hooks/useFetchAndSaveAppleEvents";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import * as AuthSession from "expo-auth-session";
import * as AppleAuthentication from "expo-apple-authentication";
import * as Notifications from 'expo-notifications';
import {useQueryClient} from "@tanstack/react-query";
import {AppleAccount, GoogleAccount, MicrosoftAccount} from "@/hooks/firebase/types/profileTypes";

const googleConfig = {
    androidClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
    iosClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
    webClientId: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
    scopes: [
        "email",
        "profile",
        "https://www.googleapis.com/auth/calendar.events.owned",
    ],
    extraParams: {
        access_type: "offline",
    },
};

const microsoftConfig = {
    clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af",
    redirectUri: AuthSession.makeRedirectUri({path: "settings"}),
    scopes: [
        "openid",
        "profile",
        "email",
        "offline_access",
        "Calendars.ReadWrite",
        "User.Read",
    ],
    authorizationEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
    tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
};

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

interface CalendarSyncResult {
    data: {
        success: boolean;
        eventCount: number;
        message?: string;
        error?: string;
    }
}

export const useCalSync = () => {
    const {profileData} = useAuthContext();
    const queryClient = useQueryClient();

    const {mutateAsync: updateUserData} = useUpdateUserData();
    const {mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle} = useFetchAndSaveGoogleEvents();
    const {mutateAsync: fetchAndSaveOutlookEvents, isLoading: isSyncingOutlook} = useFetchAndSaveMicrosoftEvents();
    const {mutateAsync: fetchAndSaveAppleEvents, isLoading: isSyncingApple} = useFetchAndSaveAppleEvents();

    WebBrowser.maybeCompleteAuthSession();
    const [_, response, promptAsync] = Google.useAuthRequest(googleConfig);

    useEffect(() => {
        signInWithGoogle();
    }, [response]);

    const signInWithGoogle = async () => {
        try {
            if (response?.type === "success") {
                const {accessToken, refreshToken} = response?.authentication!;

                const userInfoResponse = await fetch(
                    "https://www.googleapis.com/oauth2/v3/userinfo",
                    {
                        headers: {Authorization: `Bearer ${accessToken}`},
                    }
                );

                const userInfo = await userInfoResponse.json();
                const googleMail = userInfo.email;

                const googleAccount: GoogleAccount = {
                    accessToken,
                    refreshToken,
                    email: googleMail,
                    expiresAt: new Date(Date.now() + 3600 * 1000),
                    scope: googleConfig.scopes.join(' ')
                };

                await updateUserData({
                    newUserData: {
                        googleAccounts: {
                            ...profileData?.googleAccounts,
                            [googleMail]: googleAccount
                        }
                    },
                });

                await fetchAndSaveGoogleEvents({email: googleMail});
            }
        } catch (error) {
            console.error("Error during Google sign-in:", error);
            throw error;
        }
    };

    const handleMicrosoftSignIn = async () => {
        try {
            const authRequest = new AuthSession.AuthRequest({
                clientId: microsoftConfig.clientId,
                scopes: microsoftConfig.scopes,
                redirectUri: microsoftConfig.redirectUri,
                responseType: AuthSession.ResponseType.Code,
                usePKCE: true,
            });

            const authResult = await authRequest.promptAsync({
                authorizationEndpoint: microsoftConfig.authorizationEndpoint,
            });

            if (authResult.type === "success" && authResult.params?.code) {
                const code = authResult.params.code;

                const tokenResponse = await fetch(microsoftConfig.tokenEndpoint, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/x-www-form-urlencoded",
                    },
                    body: `client_id=${microsoftConfig.clientId}&redirect_uri=${encodeURIComponent(
                        microsoftConfig.redirectUri
                    )}&grant_type=authorization_code&code=${code}&code_verifier=${
                        authRequest.codeVerifier
                    }&scope=${encodeURIComponent(microsoftConfig.scopes.join(' '))}`,
                });

                if (!tokenResponse.ok) {
                    throw new Error(await tokenResponse.text());
                }

                const tokenData = await tokenResponse.json();
                const userInfoResponse = await fetch(
                    "https://graph.microsoft.com/v1.0/me",
                    {
                        headers: {
                            Authorization: `Bearer ${tokenData.access_token}`,
                        },
                    }
                );

                const userInfo = await userInfoResponse.json();
                const outlookMail = userInfo.mail || userInfo.userPrincipalName;

                const microsoftAccount: MicrosoftAccount = {
                    accessToken: tokenData.access_token,
                    refreshToken: tokenData.refresh_token,
                    email: outlookMail,
                    expiresAt: new Date(Date.now() + tokenData.expires_in * 1000),
                };

                await updateUserData({
                    newUserData: {
                        microsoftAccounts: {
                            ...profileData?.microsoftAccounts,
                            [outlookMail]: microsoftAccount
                        }
                    },
                });

                await fetchAndSaveOutlookEvents({email: outlookMail});
            }
        } catch (error) {
            console.error("Error during Microsoft sign-in:", error);
            throw error;
        }
    };

    const handleAppleSignIn = async () => {
        try {
            const credential = await AppleAuthentication.signInAsync({
                requestedScopes: [
                    AppleAuthentication.AppleAuthenticationScope.EMAIL,
                    AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
                ],
            });

            const appleToken = credential.identityToken;
            const appleMail = credential.email!;

            if (appleToken) {
                const appleAccount: AppleAccount = {
                    accessToken: appleToken,
                    email: appleMail,
                    identityToken: credential.identityToken!,
                    expiresAt: new Date(Date.now() + 3600 * 1000)
                };

                const updatedAppleAccounts = {
                    ...profileData?.appleAccounts,
                    [appleMail]: appleAccount
                };

                await updateUserData({
                    newUserData: {appleAccounts: updatedAppleAccounts},
                });

                await fetchAndSaveAppleEvents({email: appleMail});
            }
        } catch (error) {
            console.error("Error during Apple Sign-in:", error);
        }
    };
    const resyncAllCalendars = async (): Promise<void> => {
        try {
            const results: SyncResponse[] = [];

            if (profileData?.googleAccounts) {
                for (const email of Object.keys(profileData.googleAccounts)) {
                    try {
                        const result = await fetchAndSaveGoogleEvents({email});
                        results.push({
                            success: result.success,
                            eventCount: result.eventCount
                        });
                    } catch (error: any) {
                        console.error(`Failed to sync Google calendar ${email}:`, error);
                        results.push({
                            success: false,
                            error: error.message
                        });
                    }
                }
            }

            if (profileData?.microsoftAccounts) {
                for (const email of Object.keys(profileData.microsoftAccounts)) {
                    try {
                        const result = await fetchAndSaveOutlookEvents({email});
                        results.push({
                            success: result.success,
                            eventCount: result.eventCount
                        });
                    } catch (error: any) {
                        console.error(`Failed to sync Microsoft calendar ${email}:`, error);
                        results.push({
                            success: false,
                            error: error.message
                        });
                    }
                }
            }

            if (profileData?.appleAccounts) {
                for (const email of Object.keys(profileData.appleAccounts)) {
                    try {
                        const result = await fetchAndSaveAppleEvents({email});
                        results.push({
                            success: true,
                        });
                    } catch (error: any) {
                        console.error(`Failed to sync Apple calendar ${email}:`, error);
                        results.push({
                            success: false,
                            error: error.message
                        });
                    }
                }
            }

            const successCount = results.filter(r => r.success).length;
            const failCount = results.filter(r => !r.success).length;
            const totalEvents = results.reduce((sum, r) => sum + (r.eventCount || 0), 0);

            if (failCount > 0) {
                console.error(`${failCount} calendar syncs failed, ${successCount} succeeded`);
                results.filter(r => !r.success).forEach(r => {
                    console.error('Sync failed:', r.error);
                });
            } else if (successCount > 0) {
                console.log(`Successfully synced ${successCount} calendars with ${totalEvents} total events`);
            } else {
                console.log("No calendars to sync");
            }

        } catch (error) {
            console.error("Error in resyncAllCalendars:", error);
            throw error;
        }
    };


    const isConnectedToGoogle = Object.values(profileData?.googleAccounts || {}).some(account => !!account);
    const isConnectedToMicrosoft = Object.values(profileData?.microsoftAccounts || {}).some(account => !!account);
    const isConnectedToApple = Object.values(profileData?.appleAccounts || {}).some(account => !!account);

    useEffect(() => {
        const handleNotification = async (notification: Notifications.Notification) => {
            queryClient.invalidateQueries({queryKey: ["events"]});
        };

        const sub = Notifications.addNotificationReceivedListener(handleNotification);
        return () => sub.remove();
    }, []);

    return {
        handleAppleSignIn,
        handleMicrosoftSignIn,
        handleGoogleSignIn: signInWithGoogle,
        handleStartGoogleSignIn: promptAsync,
        fetchAndSaveOutlookEvents,
        fetchAndSaveAppleEvents,
        fetchAndSaveGoogleEvents,
        isConnectedToApple,
        isConnectedToMicrosoft,
        isConnectedToGoogle,
        isSyncingOutlook,
        isSyncingGoogle,
        isSyncingApple,
        resyncAllCalendars,
        isSyncing: isSyncingApple || isSyncingOutlook || isSyncingGoogle
    };
};