import 'package:riverpod_annotation/riverpod_annotation.dart'; import '../../../../core/providers/providers.dart'; import '../../data/datasources/auth_remote_datasource.dart'; import '../../data/repositories/auth_repository_impl.dart'; import '../../domain/entities/user.dart'; import '../../domain/repositories/auth_repository.dart'; part 'auth_provider.g.dart'; /// Provider for AuthRemoteDataSource @Riverpod(keepAlive: true) AuthRemoteDataSource authRemoteDataSource(Ref ref) { final dioClient = ref.watch(dioClientProvider); return AuthRemoteDataSourceImpl(dioClient: dioClient); } /// Provider for AuthRepository @Riverpod(keepAlive: true) AuthRepository authRepository(Ref ref) { final remoteDataSource = ref.watch(authRemoteDataSourceProvider); final secureStorage = ref.watch(secureStorageProvider); final dioClient = ref.watch(dioClientProvider); return AuthRepositoryImpl( remoteDataSource: remoteDataSource, secureStorage: secureStorage, dioClient: dioClient, ); } /// Auth state class class AuthState { final User? user; final bool isAuthenticated; final bool isLoading; final String? errorMessage; const AuthState({ this.user, this.isAuthenticated = false, this.isLoading = false, this.errorMessage, }); AuthState copyWith({ User? user, bool? isAuthenticated, bool? isLoading, String? errorMessage, bool clearUser = false, bool clearError = false, }) { return AuthState( user: clearUser ? null : (user ?? this.user), isAuthenticated: isAuthenticated ?? this.isAuthenticated, isLoading: isLoading ?? this.isLoading, errorMessage: clearError ? null : (errorMessage ?? this.errorMessage), ); } } /// Auth state notifier provider @Riverpod(keepAlive: true) class Auth extends _$Auth { @override AuthState build() { // Don't call async operations in build // Use a separate method to initialize auth state return const AuthState(); } AuthRepository get _repository => ref.read(authRepositoryProvider); /// Initialize auth state - call this on app start Future initialize() async { print('🚀 Initializing auth state...'); state = state.copyWith(isLoading: true); final isAuthenticated = await _repository.isAuthenticated(); print('🚀 isAuthenticated result: $isAuthenticated'); if (isAuthenticated) { print('🚀 Token found, fetching user profile...'); // Get user profile final result = await _repository.getProfile(); result.fold( (failure) { print('❌ Failed to get profile: ${failure.message}'); state = const AuthState( isAuthenticated: false, isLoading: false, ); }, (user) { print('✅ Profile loaded: ${user.name}'); state = AuthState( user: user, isAuthenticated: true, isLoading: false, ); print('✅ Initialize complete: isAuthenticated=${state.isAuthenticated}'); }, ); } else { print('❌ No token found, user needs to login'); state = const AuthState( isAuthenticated: false, isLoading: false, ); } } /// Login user Future login({ required String email, required String password, bool rememberMe = false, }) async { state = state.copyWith(isLoading: true, clearError: true); final result = await _repository.login( email: email, password: password, rememberMe: rememberMe, ); return result.fold( (failure) { print('❌ Login FAILED: ${failure.message}'); state = state.copyWith( isAuthenticated: false, isLoading: false, errorMessage: failure.message, ); return false; }, (authResponse) { print('✅ Login SUCCESS: user=${authResponse.user.name}, token length=${authResponse.accessToken.length}'); state = AuthState( user: authResponse.user, isAuthenticated: true, isLoading: false, errorMessage: null, ); print('✅ State updated: isAuthenticated=${state.isAuthenticated}'); return true; }, ); } /// Register new user Future register({ required String name, required String email, required String password, List roles = const ['user'], }) async { state = state.copyWith(isLoading: true, clearError: true); final result = await _repository.register( name: name, email: email, password: password, roles: roles, ); return result.fold( (failure) { state = state.copyWith( isAuthenticated: false, isLoading: false, errorMessage: failure.message, ); return false; }, (authResponse) { state = AuthState( user: authResponse.user, isAuthenticated: true, isLoading: false, errorMessage: null, ); return true; }, ); } /// Get user profile (refresh user data) Future getProfile() async { state = state.copyWith(isLoading: true, clearError: true); final result = await _repository.getProfile(); result.fold( (failure) { state = state.copyWith( isLoading: false, errorMessage: failure.message, ); }, (user) { state = state.copyWith( user: user, isAuthenticated: true, isLoading: false, ); }, ); } /// Refresh access token Future refreshToken() async { final result = await _repository.refreshToken(); return result.fold( (failure) { // If token refresh fails, logout user logout(); return false; }, (authResponse) { state = state.copyWith(user: authResponse.user); return true; }, ); } /// Logout user Future logout() async { state = state.copyWith(isLoading: true); await _repository.logout(); state = const AuthState( isAuthenticated: false, isLoading: false, ); } } /// Current authenticated user provider @riverpod User? currentUser(Ref ref) { final authState = ref.watch(authProvider); return authState.user; } /// Is authenticated provider @riverpod bool isAuthenticated(Ref ref) { final authState = ref.watch(authProvider); return authState.isAuthenticated; }