import '../../../../core/constants/api_endpoints.dart'; import '../../../../core/errors/exceptions.dart'; import '../../../../core/network/api_client.dart'; import '../../../../core/network/api_response.dart'; import '../models/login_request_model.dart'; import '../models/user_model.dart'; /// Abstract interface for authentication remote data source /// /// Defines the contract for authentication-related API operations abstract class AuthRemoteDataSource { /// Login with username and password /// /// Throws [ServerException] if the login fails /// Returns [UserModel] on successful login Future login(LoginRequestModel request); /// Logout current user /// /// Throws [ServerException] if logout fails Future logout(); /// Refresh access token using refresh token /// /// Throws [ServerException] if refresh fails /// Returns new [UserModel] with updated tokens Future refreshToken(String refreshToken); } /// Implementation of AuthRemoteDataSource using ApiClient /// /// Handles all authentication-related API calls class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { final ApiClient apiClient; AuthRemoteDataSourceImpl(this.apiClient); @override Future login(LoginRequestModel request) async { try { // Make POST request to login endpoint final response = await apiClient.post( ApiEndpoints.login, data: request.toJson(), ); // Parse API response with ApiResponse wrapper final apiResponse = ApiResponse.fromJson( response.data as Map, (json) => UserModel.fromJson( json as Map, username: request.username, // Pass username since API doesn't return it ), ); // Check if login was successful if (apiResponse.isSuccess && apiResponse.value != null) { return apiResponse.value!; } else { // Extract error message from API response final errorMessage = apiResponse.errors.isNotEmpty ? apiResponse.errors.first : 'Login failed'; throw ServerException( errorMessage, code: apiResponse.errorCodes.isNotEmpty ? apiResponse.errorCodes.first : null, ); } } on ServerException { rethrow; } catch (e) { throw ServerException('Failed to login: ${e.toString()}'); } } @override Future logout() async { try { // Make POST request to logout endpoint final response = await apiClient.post(ApiEndpoints.logout); // Parse API response final apiResponse = ApiResponse.fromJson( response.data as Map, null, ); // Check if logout was successful if (!apiResponse.isSuccess) { final errorMessage = apiResponse.errors.isNotEmpty ? apiResponse.errors.first : 'Logout failed'; throw ServerException( errorMessage, code: apiResponse.errorCodes.isNotEmpty ? apiResponse.errorCodes.first : null, ); } } on ServerException { rethrow; } catch (e) { throw ServerException('Failed to logout: ${e.toString()}'); } } @override Future refreshToken(String refreshToken) async { try { // Make POST request to refresh token endpoint final response = await apiClient.post( ApiEndpoints.refreshToken, data: {'refreshToken': refreshToken}, ); // Parse API response final apiResponse = ApiResponse.fromJson( response.data as Map, (json) => UserModel.fromJson(json as Map), ); // Check if refresh was successful if (apiResponse.isSuccess && apiResponse.value != null) { return apiResponse.value!; } else { final errorMessage = apiResponse.errors.isNotEmpty ? apiResponse.errors.first : 'Token refresh failed'; throw ServerException( errorMessage, code: apiResponse.errorCodes.isNotEmpty ? apiResponse.errorCodes.first : null, ); } } on ServerException { rethrow; } catch (e) { throw ServerException('Failed to refresh token: ${e.toString()}'); } } }