import 'package:flutter/foundation.dart'; import 'package:mileograph_flutter/objects/objects.dart'; import 'package:mileograph_flutter/services/api_service.dart'; import 'package:mileograph_flutter/services/token_storage_service.dart'; class AuthService extends ChangeNotifier { final ApiService api; bool _restoring = false; final TokenStorageService _tokenStorage = TokenStorageService(); AuthService({required this.api}) { api.setTokenProvider(() => token); api.setUnauthorizedHandler(handleTokenExpired); } AuthenticatedUserData? _user; bool get isLoggedIn => _user != null; String? get token => _user?.accessToken; String? get userId => _user?.userId; String? get username => _user?.username; String? get fullName => _user?.fullName; void setLoginData({ required String userId, required String username, required String fullName, required String accessToken, required String email, }) { _user = AuthenticatedUserData( userId: userId, username: username, fullName: fullName, accessToken: accessToken, email: email, ); _persistToken(accessToken); notifyListeners(); } Future login(String username, String password) async { final formData = { 'grant_type': 'password', 'username': username, 'password': password, 'scope': '', 'client_id': 'string', 'client_secret': 'string', }; // 1. Get token final tokenResponse = await api.postForm('/token', formData); final accessToken = tokenResponse['access_token']; // 2. Get user details final userResponse = await api.get( '/users/me', headers: { 'Authorization': 'Bearer $accessToken', 'accept': 'application/json', }, ); // 3. Populate state setLoginData( userId: userResponse['user_id'], username: userResponse['username'], fullName: userResponse['full_name'], accessToken: accessToken, email: userResponse['email'], ); } Future tryRestoreSession() async { if (_restoring || _user != null) return; _restoring = true; try { // read token from secure storage (with fallback) final token = await _tokenStorage.getToken(); if (token == null || token.isEmpty) return; final userResponse = await api.get( '/users/me', headers: { 'Authorization': 'Bearer $token', 'accept': 'application/json', }, ); setLoginData( userId: userResponse['user_id'], username: userResponse['username'], fullName: userResponse['full_name'], accessToken: token, email: userResponse['email'], ); } catch (_) { await _clearToken(); } finally { _restoring = false; } } Future validateStoredToken() async { final token = await _tokenStorage.getToken(); if (token == null || token.isEmpty) return false; try { await api.get( '/validate', headers: { 'Authorization': 'Bearer $token', 'accept': 'application/json', }, ); return true; } catch (_) { await _clearToken(); return false; } } Future _persistToken(String token) async { await _tokenStorage.setToken(token); } Future _clearToken() async { await _tokenStorage.clearToken(); } Future register({ required String username, required String email, required String fullName, required String password, String inviteCode = '', }) async { final formData = { 'user_name': username, 'email': email, 'full_name': fullName, 'password': password, 'invitation_code': inviteCode, 'empty': '', 'empty2': '', }; await api.postForm('/register', formData); } Future handleTokenExpired() async { _user = null; await _clearToken(); notifyListeners(); } void logout() { handleTokenExpired(); // reuse } }