import {useAuthContext} from "@/contexts/AuthContext";
import {useEffect} from "react";
import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData";
import {useFetchAndSaveGoogleEvents} from "@/hooks/useFetchAndSaveGoogleEvents";
import {useFetchAndSaveOutlookEvents} 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";

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",
};

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

    const {mutateAsync: updateUserData} = useUpdateUserData();
    const {mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle} =
        useFetchAndSaveGoogleEvents();
    const {
        mutateAsync: fetchAndSaveOutlookEvents,
        isLoading: isSyncingOutlook,
    } = useFetchAndSaveOutlookEvents();
    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;

                let googleAccounts = profileData?.googleAccounts || {};
                const updatedGoogleAccounts = {
                    ...googleAccounts,
                    [googleMail]: {accessToken, refreshToken},
                };

                await updateUserData({
                    newUserData: {googleAccounts: updatedGoogleAccounts},
                });

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

    const handleMicrosoftSignIn = async () => {
        try {
            console.log("Starting Microsoft sign-in...");

            const authRequest = new AuthSession.AuthRequest({
                clientId: microsoftConfig.clientId,
                scopes: microsoftConfig.scopes,
                redirectUri: microsoftConfig.redirectUri,
                responseType: AuthSession.ResponseType.Code,
                usePKCE: true, // Enable PKCE
            });

            console.log("Auth request created:", authRequest);

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

            console.log("Auth result:", authResult);

            if (authResult.type === "success" && authResult.params?.code) {
                const code = authResult.params.code;
                console.log("Authorization code received:", code);

                // Exchange authorization code for tokens
                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(
                        "https://graph.microsoft.com/Calendars.ReadWrite offline_access User.Read"
                    )}`,
                });

                console.log("Token response status:", tokenResponse.status);

                if (!tokenResponse.ok) {
                    const errorText = await tokenResponse.text();
                    console.error("Token exchange failed:", errorText);
                    return;
                }

                const tokenData = await tokenResponse.json();
                console.log("Token data received:", tokenData);

                if (tokenData?.access_token) {
                    console.log("Access token received, fetching user info...");

                    // Fetch user info from Microsoft Graph API to get the email
                    const userInfoResponse = await fetch(
                        "https://graph.microsoft.com/v1.0/me",
                        {
                            headers: {
                                Authorization: `Bearer ${tokenData.access_token}`,
                            },
                        }
                    );

                    const userInfo = await userInfoResponse.json();
                    console.log("User info received:", userInfo);

                    if (userInfo.error) {
                        console.error("Error fetching user info:", userInfo.error);
                    } else {
                        const outlookMail = userInfo.mail || userInfo.userPrincipalName;

                        let microsoftAccounts = profileData?.microsoftAccounts;
                        const updatedMicrosoftAccounts = microsoftAccounts
                            ? {...microsoftAccounts, [outlookMail]: tokenData.access_token}
                            : {[outlookMail]: tokenData.access_token};

                        await updateUserData({
                            newUserData: {microsoftAccounts: updatedMicrosoftAccounts},
                        });

                        await fetchAndSaveOutlookEvents(
                            tokenData.access_token,
                            outlookMail
                        );
                        console.log("User data updated successfully.");
                    }
                }
            } else {
                console.warn("Authentication was not successful:", authResult);
            }
        } catch (error) {
            console.error("Error during Microsoft sign-in:", error);
        }
    };

    const handleAppleSignIn = async () => {
        try {
            console.log("Starting Apple Sign-in...");

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

            console.log("Apple sign-in result:", credential);

            alert(JSON.stringify(credential))

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


            if (appleToken) {
                console.log("Apple ID token received. Fetch user info if needed...");

                let appleAcounts = profileData?.appleAccounts;
                const updatedAppleAccounts = appleAcounts
                    ? {...appleAcounts, [appleMail]: appleToken}
                    : {[appleMail]: appleToken};

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

                console.log("User data updated with Apple ID token.");
                await fetchAndSaveAppleEvents({token: appleToken, email: appleMail!});
            } else {
                console.warn(
                    "Apple authentication was not successful or email was hidden."
                );
            }
        } catch (error) {
            console.error("Error during Apple Sign-in:", error);
        }
    };


    let isConnectedToGoogle = false;
    if (profileData?.googleAccounts) {
        Object.values(profileData?.googleAccounts).forEach((item) => {
            if (item !== null) {
                isConnectedToGoogle = true;
                return;
            }
        });
    }

    let isConnectedToMicrosoft = false;
    const microsoftAccounts = profileData?.microsoftAccounts;
    if (microsoftAccounts) {
        Object.values(profileData?.microsoftAccounts).forEach((item) => {
            if (item !== null) {
                isConnectedToMicrosoft = true;
                return;
            }
        });
    }

    let isConnectedToApple = false;
    if (profileData?.appleAccounts) {
        Object.values(profileData?.appleAccounts).forEach((item) => {
            if (item !== null) {
                isConnectedToApple = true;
                return;
            }
        });
    }


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