import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/api/client.dart'; import '../core/api/endpoints.dart'; import '../core/api/exceptions.dart'; import '../models/auth.dart'; enum AuthStatus { initial, authenticated, unauthenticated, loading } class AuthState { final AuthStatus status; final User? user; final String? error; final bool needsTwoFactor; AuthState({ this.status = AuthStatus.initial, this.user, this.error, this.needsTwoFactor = false, }); AuthState copyWith({ AuthStatus? status, User? user, String? error, bool? needsTwoFactor, }) => AuthState( status: status ?? this.status, user: user ?? this.user, error: error, needsTwoFactor: needsTwoFactor ?? this.needsTwoFactor, ); } class AuthNotifier extends StateNotifier { final ApiClient _api; AuthNotifier(this._api) : super(AuthState()) { _checkAuth(); } Future _checkAuth() async { final token = await _api.getAccessToken(); if (token != null) { state = state.copyWith(status: AuthStatus.authenticated); } else { state = state.copyWith(status: AuthStatus.unauthenticated); } } Future login(String email, String password) async { state = state.copyWith(status: AuthStatus.loading, error: null); try { final response = await _api.post(Endpoints.login, data: { 'email': email, 'password': password, }); final authResponse = AuthResponse.fromJson( response.data as Map); if (authResponse.user.isTwoFactorEnabled) { state = state.copyWith( status: AuthStatus.unauthenticated, needsTwoFactor: true, ); return; } await _api.saveTokens( authResponse.accessToken, authResponse.refreshToken); state = state.copyWith( status: AuthStatus.authenticated, user: authResponse.user, ); } on ApiException catch (e) { state = state.copyWith( status: AuthStatus.unauthenticated, error: e.message, ); } } Future register(String email, String password, String name) async { state = state.copyWith(status: AuthStatus.loading, error: null); try { final response = await _api.post(Endpoints.register, data: { 'email': email, 'password': password, 'name': name, }); final authResponse = AuthResponse.fromJson( response.data as Map); await _api.saveTokens( authResponse.accessToken, authResponse.refreshToken); state = state.copyWith( status: AuthStatus.authenticated, user: authResponse.user, ); } on ApiException catch (e) { state = state.copyWith( status: AuthStatus.unauthenticated, error: e.message, ); } } Future verifyTwoFactor(String code) async { state = state.copyWith(status: AuthStatus.loading, error: null); try { final response = await _api.post(Endpoints.twoFactor, data: { 'code': code, }); final authResponse = AuthResponse.fromJson( response.data as Map); await _api.saveTokens( authResponse.accessToken, authResponse.refreshToken); state = state.copyWith( status: AuthStatus.authenticated, user: authResponse.user, needsTwoFactor: false, ); } on ApiException catch (e) { state = state.copyWith( status: AuthStatus.unauthenticated, error: e.message, ); } } Future logout() async { await _api.clearTokens(); state = AuthState(status: AuthStatus.unauthenticated); } Future forgotPassword(String email) async { state = state.copyWith(status: AuthStatus.loading, error: null); try { await _api.post(Endpoints.forgotPassword, data: {'email': email}); state = state.copyWith(status: AuthStatus.unauthenticated); } on ApiException catch (e) { state = state.copyWith( status: AuthStatus.unauthenticated, error: e.message); } } Future resetPassword(String token, String password) async { state = state.copyWith(status: AuthStatus.loading, error: null); try { await _api.post(Endpoints.resetPassword, data: { 'token': token, 'password': password, }); state = state.copyWith(status: AuthStatus.unauthenticated); } on ApiException catch (e) { state = state.copyWith( status: AuthStatus.unauthenticated, error: e.message); } } Future getOAuthUrl(String provider) async { try { final response = await _api.get('${Endpoints.oauth}/$provider'); return response.data['url'] as String?; } catch (_) { return null; } } void clearError() { state = state.copyWith(error: null); } } final authProvider = StateNotifierProvider((ref) { final api = ref.read(apiClientProvider); return AuthNotifier(api); });