'use client'; import React, { createContext, useContext, useEffect, useState, useCallback } from 'react'; import { AuthUser, AuthState, AuthConfig } from '../types'; import { getAuthInstance, initAuth } from '../services/auth.service'; interface AuthContextValue extends AuthState { signIn: (email: string, password: string, rememberMe?: boolean) => Promise; signUp: (email: string, password: string, displayName?: string) => Promise; signOut: () => Promise; signInWithProvider: (provider: 'google' | 'github') => Promise; sendPasswordResetEmail: (email: string) => Promise; refreshUser: () => Promise; } const AuthContext = createContext(undefined); interface AuthProviderProps { children: React.ReactNode; config?: AuthConfig; } export function AuthProvider({ children, config }: AuthProviderProps) { const [state, setState] = useState({ user: null, loading: true, error: null, isAuthenticated: false, }); // Initialize auth service if config provided useEffect(() => { if (config) { initAuth(config); } }, [config]); // Subscribe to auth state changes useEffect(() => { try { const auth = getAuthInstance(); const unsubscribe = auth.onAuthStateChange((user) => { setState({ user, loading: false, error: null, isAuthenticated: !!user, }); }); return unsubscribe; } catch (error) { setState({ user: null, loading: false, error: { code: 'auth/not-initialized', message: 'Auth not initialized. Provide config to AuthProvider.', }, isAuthenticated: false, }); return () => {}; // Return empty cleanup function } }, []); const signIn = useCallback(async (email: string, password: string, rememberMe = false) => { setState(prev => ({ ...prev, loading: true, error: null })); try { const auth = getAuthInstance(); const { user } = await auth.signIn({ email, password, rememberMe }); setState({ user, loading: false, error: null, isAuthenticated: true, }); return user; } catch (error: any) { setState(prev => ({ ...prev, loading: false, error, })); throw error; } }, []); const signUp = useCallback(async (email: string, password: string, displayName?: string) => { setState(prev => ({ ...prev, loading: true, error: null })); try { const auth = getAuthInstance(); const { user } = await auth.signUp({ email, password, displayName }); setState({ user, loading: false, error: null, isAuthenticated: true, }); return user; } catch (error: any) { setState(prev => ({ ...prev, loading: false, error, })); throw error; } }, []); const signOut = useCallback(async () => { setState(prev => ({ ...prev, loading: true, error: null })); try { const auth = getAuthInstance(); await auth.signOut(); setState({ user: null, loading: false, error: null, isAuthenticated: false, }); } catch (error: any) { setState(prev => ({ ...prev, loading: false, error, })); throw error; } }, []); const signInWithProvider = useCallback(async (provider: 'google' | 'github') => { setState(prev => ({ ...prev, loading: true, error: null })); try { const auth = getAuthInstance(); const { user } = await auth.signInWith(provider); setState({ user, loading: false, error: null, isAuthenticated: true, }); return user; } catch (error: any) { setState(prev => ({ ...prev, loading: false, error, })); throw error; } }, []); const sendPasswordResetEmail = useCallback(async (email: string) => { try { const auth = getAuthInstance(); await auth.sendPasswordResetEmail(email); } catch (error: any) { setState(prev => ({ ...prev, error, })); throw error; } }, []); const refreshUser = useCallback(async () => { if (!state.user) return; setState(prev => ({ ...prev, loading: true })); try { // Force token refresh to get latest custom claims await state.user.getIdToken(true); const auth = getAuthInstance(); const currentUser = auth.getCurrentUser(); setState(prev => ({ ...prev, user: currentUser, loading: false, })); } catch (error: any) { setState(prev => ({ ...prev, loading: false, error, })); } }, [state.user]); const value: AuthContextValue = { ...state, signIn, signUp, signOut, signInWithProvider, sendPasswordResetEmail, refreshUser, }; return {children}; } export function useAuthContext() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuthContext must be used within an AuthProvider'); } return context; }