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<UserModel> login(LoginRequestModel request);

  /// Logout current user
  ///
  /// Throws [ServerException] if logout fails
  Future<void> logout();

  /// Refresh access token using refresh token
  ///
  /// Throws [ServerException] if refresh fails
  /// Returns new [UserModel] with updated tokens
  Future<UserModel> 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<UserModel> 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<String, dynamic>,
        (json) => UserModel.fromJson(
          json as Map<String, dynamic>,
          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<void> 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<String, dynamic>,
        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<UserModel> 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<String, dynamic>,
        (json) => UserModel.fromJson(json as Map<String, dynamic>),
      );

      // 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()}');
    }
  }
}
