import 'package:dio/dio.dart';
import 'package:real_estate_mobile/core/constants/api_constants.dart';
import 'package:real_estate_mobile/core/network/api_client.dart';
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
import 'package:real_estate_mobile/core/storage/secure_storage.dart';
import 'package:real_estate_mobile/features/auth/data/models/auth_response.dart';
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';

class AuthRepository {
  final Dio _dio = ApiClient.instance.dio;

  /// Extract a user-friendly message from a DioException.
  /// NEVER returns Dio's raw technical text — always a short human sentence.
  static String _friendlyError(DioException e, String fallback) {
    // If our interceptor already wrapped it, use that message
    if (e.error is ApiException) return (e.error as ApiException).message;
    // Status-code based fallback
    switch (e.response?.statusCode) {
      case 400: return 'The request was invalid. Please check your input.';
      case 401: return 'Invalid email or password.';
      case 403: return 'You don\'t have permission to perform this action.';
      case 404: return 'Not found.';
      case 409: return 'This action conflicts with existing data.';
      case 429: return 'Too many attempts. Please wait and try again.';
    }
    if (e.type == DioExceptionType.connectionTimeout ||
        e.type == DioExceptionType.receiveTimeout ||
        e.type == DioExceptionType.sendTimeout) {
      return 'Request timed out. Please check your connection.';
    }
    if (e.type == DioExceptionType.connectionError) {
      return 'Unable to reach the server. Check your internet connection.';
    }
    return fallback;
  }

  Future<Map<String, dynamic>> login({
    required String email,
    required String password,
    String? loginRole,
  }) async {
    try {
      final response = await _dio.post(
        ApiConstants.authLogin,
        data: {
          'email': email,
          'password': password,
          if (loginRole != null) 'loginRole': loginRole,
        },
      );

      final data = response.data['data'] as Map<String, dynamic>;

      // Check if 2FA is required
      if (data['requiresTwoFactor'] == true) {
        return {
          'requiresTwoFactor': true,
          'tempToken': data['tempToken'],
        };
      }

      final authResponse = AuthResponse.fromJson(data);

      await SecureStorage.saveTokens(
        accessToken: authResponse.accessToken,
        refreshToken: authResponse.refreshToken,
      );

      return {
        'requiresTwoFactor': false,
        'user': authResponse.user,
      };
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, 'Login failed'),
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// Verify 2FA TOTP token during login
  Future<AuthResponse> verifyTwoFactor({
    required String tempToken,
    required String token,
  }) async {
    try {
      final response = await _dio.post(
        ApiConstants.twoFactorVerify,
        data: {'tempToken': tempToken, 'token': token},
      );
      final data = response.data['data'] as Map<String, dynamic>;
      final authResponse = AuthResponse.fromJson(data);
      await SecureStorage.saveTokens(
        accessToken: authResponse.accessToken,
        refreshToken: authResponse.refreshToken,
      );
      return authResponse;
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, '2FA verification failed'),
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// Verify backup code during login
  Future<AuthResponse> verifyBackupCode({
    required String tempToken,
    required String backupCode,
  }) async {
    try {
      final response = await _dio.post(
        ApiConstants.twoFactorVerifyBackup,
        data: {'tempToken': tempToken, 'backupCode': backupCode},
      );
      final data = response.data['data'] as Map<String, dynamic>;
      final authResponse = AuthResponse.fromJson(data);
      await SecureStorage.saveTokens(
        accessToken: authResponse.accessToken,
        refreshToken: authResponse.refreshToken,
      );
      return authResponse;
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, 'Backup code verification failed'),
        statusCode: e.response?.statusCode,
      );
    }
  }

  Future<UserModel> getMe() async {
    try {
      final response = await _dio.get(ApiConstants.authMe);
      final data = response.data['data'] as Map<String, dynamic>;
      return UserModel.fromJson(data);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, 'Failed to fetch user'),
        statusCode: e.response?.statusCode,
      );
    }
  }

  Future<void> logout() async {
    try {
      await _dio.post(ApiConstants.authLogout);
    } catch (_) {
      // Ignore logout API errors — still clear local tokens
    } finally {
      await SecureStorage.clearTokens();
    }
  }

  /// Social auth (Google, Facebook, etc.) — calls POST /auth/social
  Future<UserModel> socialAuth({
    required String provider,
    required String providerId,
    required String email,
    String? name,
    String? avatar,
    String? role,
    String? agentTypeId,
    String mode = 'signup',
  }) async {
    try {
      final response = await _dio.post(
        ApiConstants.authSocial,
        data: {
          'provider': provider,
          'providerId': providerId,
          'email': email,
          'mode': mode,
          if (name != null) 'name': name,
          if (avatar != null) 'avatar': avatar,
          if (role != null) 'role': role,
          if (agentTypeId != null) 'agentTypeId': agentTypeId,
        },
      );

      final data = response.data['data'] as Map<String, dynamic>;
      final authResponse = AuthResponse.fromJson(data);

      await SecureStorage.saveTokens(
        accessToken: authResponse.accessToken,
        refreshToken: authResponse.refreshToken,
      );

      return authResponse.user;
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, 'Social login failed'),
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// Register returns { message, user } — no tokens.
  /// The user must verify their email before logging in.
  Future<Map<String, dynamic>> register(RegisterRequest request) async {
    try {
      final response = await _dio.post(
        ApiConstants.authRegister,
        data: request.toJson(),
      );

      final data = response.data['data'] as Map<String, dynamic>;
      return data;
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: _friendlyError(e, 'Registration failed'),
        statusCode: e.response?.statusCode,
      );
    }
  }
}
