import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../../../../core/config/app_config.dart'; import '../../../../core/errors/exceptions.dart'; import '../../../../core/logging/app_logger.dart'; import '../models/token_model.dart'; import '../models/user_model.dart'; abstract class AuthRemoteDataSource { Future register({ required String email, required String password, required String name, }); Future login({ required String email, required String password, }); Future getCurrentUser(String accessToken); Future refreshToken(String refreshToken); } class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { final AppLogger logger; final http.Client _client; String get _baseUrl => AppConfig.current.apiBaseUrl; AuthRemoteDataSourceImpl({ required this.logger, http.Client? client, }) : _client = client ?? http.Client(); Map get _headers => { 'Content-Type': 'application/json', 'Accept': 'application/json', }; Map _authHeaders(String token) => { ..._headers, 'Authorization': 'Bearer $token', }; @override Future register({ required String email, required String password, required String name, }) async { final uri = Uri.parse('$_baseUrl/auth/register'); logger.info('POST $uri'); try { final response = await _client.post( uri, headers: _headers, body: json.encode({ 'email': email, 'password': password, 'name': name, }), ); logger.debug('Response: ${response.statusCode}'); if (response.statusCode == 201 || response.statusCode == 200) { return UserModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 400) { final body = json.decode(response.body); throw AuthException( message: body['detail'] ?? 'Registration failed', ); } else { throw ServerException( message: 'Registration failed', statusCode: response.statusCode, ); } } on SocketException { throw const NetworkException(); } } @override Future login({ required String email, required String password, }) async { final uri = Uri.parse('$_baseUrl/auth/login'); logger.info('POST $uri'); try { final response = await _client.post( uri, headers: _headers, body: json.encode({ 'email': email, 'password': password, }), ); logger.debug('Response: ${response.statusCode}'); if (response.statusCode == 200) { return TokenModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw const AuthException(message: 'Invalid email or password'); } else { throw ServerException( message: 'Login failed', statusCode: response.statusCode, ); } } on SocketException { throw const NetworkException(); } } @override Future getCurrentUser(String accessToken) async { final uri = Uri.parse('$_baseUrl/auth/me'); logger.info('GET $uri'); try { final response = await _client.get( uri, headers: _authHeaders(accessToken), ); logger.debug('Response: ${response.statusCode}'); if (response.statusCode == 200) { return UserModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw const UnauthorizedException(); } else { throw ServerException( message: 'Failed to get user info', statusCode: response.statusCode, ); } } on SocketException { throw const NetworkException(); } } @override Future refreshToken(String refreshToken) async { final uri = Uri.parse('$_baseUrl/auth/refresh'); logger.info('POST $uri'); try { final response = await _client.post( uri, headers: _headers, body: json.encode({'refresh_token': refreshToken}), ); logger.debug('Response: ${response.statusCode}'); if (response.statusCode == 200) { return TokenModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw const UnauthorizedException(message: 'Session expired'); } else { throw ServerException( message: 'Token refresh failed', statusCode: response.statusCode, ); } } on SocketException { throw const NetworkException(); } } }