import 'package:equatable/equatable.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../data/models/login_request_model.dart'; import '../../domain/entities/user_entity.dart'; import '../../domain/usecases/login_usecase.dart'; /// Authentication state /// /// Represents the current authentication status and user data class AuthState extends Equatable { /// Current authenticated user (null if not authenticated) final UserEntity? user; /// Whether user is authenticated final bool isAuthenticated; /// Whether an authentication operation is in progress final bool isLoading; /// Error message if authentication fails final String? error; const AuthState({ this.user, this.isAuthenticated = false, this.isLoading = false, this.error, }); /// Initial state (not authenticated, not loading) const AuthState.initial() : user = null, isAuthenticated = false, isLoading = false, error = null; /// Loading state const AuthState.loading() : user = null, isAuthenticated = false, isLoading = true, error = null; /// Authenticated state with user data const AuthState.authenticated(UserEntity user) : user = user, isAuthenticated = true, isLoading = false, error = null; /// Error state const AuthState.error(String message) : user = null, isAuthenticated = false, isLoading = false, error = message; /// Create a copy with modified fields AuthState copyWith({ UserEntity? user, bool? isAuthenticated, bool? isLoading, String? error, }) { return AuthState( user: user ?? this.user, isAuthenticated: isAuthenticated ?? this.isAuthenticated, isLoading: isLoading ?? this.isLoading, error: error, ); } @override List get props => [user, isAuthenticated, isLoading, error]; @override String toString() { return 'AuthState(isAuthenticated: $isAuthenticated, isLoading: $isLoading, error: $error, user: $user)'; } } /// Auth state notifier that manages authentication state /// /// Handles login, logout, and authentication status checks class AuthNotifier extends StateNotifier { final LoginUseCase loginUseCase; final LogoutUseCase logoutUseCase; final CheckAuthStatusUseCase checkAuthStatusUseCase; final GetCurrentUserUseCase getCurrentUserUseCase; AuthNotifier({ required this.loginUseCase, required this.logoutUseCase, required this.checkAuthStatusUseCase, required this.getCurrentUserUseCase, }) : super(const AuthState.initial()); /// Login with username and password /// /// Updates state to loading, then either authenticated or error Future login(String username, String password) async { // Set loading state state = const AuthState.loading(); // Create login request final request = LoginRequestModel( username: username, password: password, ); // Call login use case final result = await loginUseCase(request); // Handle result result.fold( (failure) { // Login failed - set error state state = AuthState.error(failure.message); }, (user) { // Login successful - set authenticated state state = AuthState.authenticated(user); }, ); } /// Logout current user /// /// Clears authentication data and returns to initial state Future logout() async { // Clear tokens from secure storage await logoutUseCase(); // Always reset to initial state (clear local data even if API call fails) state = const AuthState.initial(); } /// Check authentication status on app start /// /// Loads user data from storage if authenticated Future checkAuthStatus() async { // Check if user is authenticated final isAuthenticated = await checkAuthStatusUseCase(); if (isAuthenticated) { // Try to load user data final result = await getCurrentUserUseCase(); result.fold( (failure) { // Failed to load user data - reset to initial state state = const AuthState.initial(); }, (user) { // User data loaded - set authenticated state state = AuthState.authenticated(user); }, ); } else { // Not authenticated - initial state state = const AuthState.initial(); } } /// Clear error message void clearError() { if (state.error != null) { state = state.copyWith(error: null); } } /// Reset to initial state void reset() { state = const AuthState.initial(); } }