import { useMutation, useQueryClient } from "react-query";
import { useAuthContext } from "@/contexts/AuthContext";
import { useSetUserData } from "@/hooks/firebase/useSetUserData";
import functions from '@react-native-firebase/functions';
import * as AuthSession from 'expo-auth-session';

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

interface SyncError extends Error {
    code?: string;
    details?: {
        requiresReauth?: boolean;
        message?: string;
    };
}

const microsoftConfig = {
    clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af",
    scopes: [
        "openid",
        "profile",
        "email",
        "offline_access",
        "Calendars.ReadWrite",
        "User.Read",
    ],
    redirectUri: AuthSession.makeRedirectUri({path: "settings"})
};

export const useFetchAndSaveMicrosoftEvents = () => {
    const queryClient = useQueryClient();
    const { profileData } = useAuthContext();
    const { mutateAsync: setUserData } = useSetUserData();

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

            const result = await authRequest.promptAsync({
                authorizationEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
            });

            if (result.type === 'success' && result.params?.code) {
                const tokenResponse = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                    },
                    body: new URLSearchParams({
                        client_id: microsoftConfig.clientId,
                        scope: microsoftConfig.scopes.join(' '),
                        code: result.params.code,
                        redirect_uri: microsoftConfig.redirectUri,
                        grant_type: 'authorization_code',
                        code_verifier: authRequest.codeVerifier || '',
                    }),
                });

                const tokens = await tokenResponse.json();

                await setUserData({
                    newUserData: {
                        microsoftAccounts: {
                            ...profileData?.microsoftAccounts,
                            [email]: {
                                accessToken: tokens.access_token,
                                refreshToken: tokens.refresh_token,
                                email,
                            }
                        }
                    }
                });

                return true;
            }
            return false;
        } catch (error) {
            console.error('Microsoft reauth error:', error);
            return false;
        }
    };

    return useMutation<SyncResponse, SyncError, { email?: string }>({
        mutationKey: ["fetchAndSaveOutlookEvents", "sync"],
        mutationFn: async ({ email }: { email?: string }) => {
            if (!email) {
                throw new Error("Email is required");
            }

            if (!profileData?.microsoftAccounts?.[email]) {
                throw new Error("No valid Microsoft account found");
            }

            try {
                const response = await functions()
                    .httpsCallable('triggerMicrosoftSync')({ email });

                return response.data as SyncResponse;
            } catch (error: any) {
                console.error("Microsoft sync error:", error);

                // Check if we need to reauthenticate
                if (error.details?.requiresReauth ||
                    error.code === 'functions/failed-precondition' ||
                    error.code === 'functions/unauthenticated') {

                    console.log('Attempting Microsoft reauth...');
                    const reauthSuccessful = await handleReauth(email);

                    if (reauthSuccessful) {
                        // Retry the sync with new tokens
                        console.log('Retrying sync after reauth...');
                        const retryResponse = await functions()
                            .httpsCallable('triggerMicrosoftSync')({ email });
                        return retryResponse.data as SyncResponse;
                    }
                }

                throw error;
            }
        },
        onSuccess: (data) => {
            queryClient.invalidateQueries(["events"]);
            console.log(`Successfully synced ${data.eventCount} Microsoft events`);
        },
        onError: (error) => {
            console.error('Microsoft sync failed:', {
                message: error.message,
                code: error.code,
                details: error.details
            });
        }
    });
};