import 'dart:convert';
import 'package:dio/dio.dart';

import '../../../../core/constants/api_constants.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/network/dio_client.dart';
import '../models/user_model.dart';

abstract class AuthRemoteDataSource {
  Future<UserModel> login({required String email, required String password});
  Future<UserModel> register({
    required String firstName,
    required String lastName,
    required String email,
    required String password,
    String? referralCode,
  });
  Future<void> logout();
  Future<UserModel> verifyTwoFactor(
      {required String userId, required String code});
  Future<void> refreshToken();
  Future<void> requestPasswordReset({required String email});
  Future<void> resetPassword(
      {required String token, required String newPassword});
  Future<void> changePassword(
      {required String currentPassword, required String newPassword});
  Future<void> verifyEmail({required String token});
  Future<void> resendEmailVerification();
  Future<UserModel> googleSignIn({required String idToken});
  Future<Map<String, dynamic>> enableTwoFactor({required String type});
  Future<void> disableTwoFactor({required String code});
  Future<UserModel> updateProfile({
    String? firstName,
    String? lastName,
    String? phone,
    String? avatar,
  });
}

class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final DioClient client;
  String? _tempAccessToken;
  String? _tempSessionId;
  String? _tempCsrfToken;

  AuthRemoteDataSourceImpl({required this.client});

  // Getters for tokens
  String? get lastAccessToken => _tempAccessToken;
  String? get lastSessionId => _tempSessionId;
  String? get lastCsrfToken => _tempCsrfToken;

  void clearTokens() {
    _tempAccessToken = null;
    _tempSessionId = null;
    _tempCsrfToken = null;
  }

  @override
  Future<UserModel> login(
      {required String email, required String password}) async {
    print('🔵 AUTH_REMOTE_DS: Starting login for email: $email');

    try {
      print('🔵 AUTH_REMOTE_DS: Making POST request to ${ApiConstants.login}');
      print(
          '🔵 AUTH_REMOTE_DS: Request data: {email: $email, password: [HIDDEN]}');

      final response = await client.post(
        ApiConstants.login,
        data: {
          'email': email,
          'password': password,
        },
      );

      print(
          '🔵 AUTH_REMOTE_DS: Response received - Status: ${response.statusCode}');
      print('🔵 AUTH_REMOTE_DS: Response headers: ${response.headers}');
      print('🔵 AUTH_REMOTE_DS: Response data: ${response.data}');

      if (response.statusCode == 200) {
        final data = response.data;

        print('🔵 AUTH_REMOTE_DS: Checking response structure...');
        print('🔵 AUTH_REMOTE_DS: Has twoFactor: ${data['twoFactor'] != null}');
        print('🔵 AUTH_REMOTE_DS: Has user: ${data['user'] != null}');
        print('🔵 AUTH_REMOTE_DS: Has message: ${data['message'] != null}');
        print('🔵 AUTH_REMOTE_DS: Has cookies: ${data['cookies'] != null}');

        // Check if 2FA is required
        if (data['twoFactor'] != null && data['twoFactor']['enabled'] == true) {
          print(
              '🔴 AUTH_REMOTE_DS: 2FA required - userId: ${data['id']}, type: ${data['twoFactor']['type']}');
          throw AuthException(
              '2FA required for user ${data['id']} with type ${data['twoFactor']['type']}');
        }

        // Handle successful login with cookies/tokens format
        if (data['cookies'] != null && data['message'] != null) {
          print('🔵 AUTH_REMOTE_DS: Login successful with cookies format');
          final cookies = data['cookies'];
          final accessToken = cookies['accessToken'];
          final sessionId = cookies['sessionId'];
          final csrfToken = cookies['csrfToken'];

          print('🔵 AUTH_REMOTE_DS: Extracting user info from access token');

          // Extract user info from JWT token
          final userInfo = _extractUserFromJWT(accessToken);
          print('🔵 AUTH_REMOTE_DS: Extracted user info: $userInfo');

          // Store tokens globally for later use
          _tempAccessToken = accessToken;
          _tempSessionId = sessionId;
          _tempCsrfToken = csrfToken;

          // Create user model with extracted info and email
          final userModel = UserModel(
            id: userInfo['id'],
            email: email, // Use the email from login request
            firstName:
                'User', // Default name, will be updated from profile API later
            lastName:
                '', // Default name, will be updated from profile API later
            role: userInfo['role'].toString(),
            emailVerified: true, // Assume verified since login was successful
            status: 'ACTIVE',
            avatar: null,
            phone: null,
            emailVerifiedAt: DateTime.now(),
            createdAt: DateTime.now(),
            updatedAt: DateTime.now(),
          );

          print(
              '🟢 AUTH_REMOTE_DS: Login successful, created UserModel for: $email');
          return userModel;
        }

        // Fallback for direct user data response (if API format changes)
        if (data['user'] != null) {
          print(
              '🟢 AUTH_REMOTE_DS: Login successful with direct user data format');
          return UserModel.fromJson(data['user']);
        }

        print('🔴 AUTH_REMOTE_DS: Unexpected response format');
        throw const FormatException(
            'Unexpected response format from login API');
      } else {
        print(
            '🔴 AUTH_REMOTE_DS: Login failed with status: ${response.statusCode}');
        throw ServerException('Login failed');
      }
    } on DioException catch (e) {
      print('🔴 AUTH_REMOTE_DS: DioException caught');
      print('🔴 AUTH_REMOTE_DS: Error type: ${e.type}');
      print('🔴 AUTH_REMOTE_DS: Error message: ${e.message}');
      print('🔴 AUTH_REMOTE_DS: Response status: ${e.response?.statusCode}');
      print('🔴 AUTH_REMOTE_DS: Response data: ${e.response?.data}');
      throw _handleDioException(e);
    } catch (e) {
      print('🔴 AUTH_REMOTE_DS: General exception caught: $e');
      print('🔴 AUTH_REMOTE_DS: Exception type: ${e.runtimeType}');
      if (e is AuthException) {
        print('🔴 AUTH_REMOTE_DS: Re-throwing AuthException');
        rethrow;
      }
      throw ServerException('Unexpected error during login');
    }
  }

  // Helper method to extract user info from JWT token
  Map<String, dynamic> _extractUserFromJWT(String token) {
    try {
      print('🔵 AUTH_REMOTE_DS: Decoding JWT token');

      // JWT tokens have 3 parts separated by dots: header.payload.signature
      final parts = token.split('.');
      if (parts.length != 3) {
        throw FormatException('Invalid JWT token format');
      }

      // Decode the payload (second part)
      final payload = parts[1];

      // Add padding if necessary (JWT base64 encoding might not have padding)
      String normalizedPayload = payload;
      switch (payload.length % 4) {
        case 1:
          normalizedPayload += '===';
          break;
        case 2:
          normalizedPayload += '==';
          break;
        case 3:
          normalizedPayload += '=';
          break;
      }

      // Decode base64
      final decodedBytes = base64Url.decode(normalizedPayload);
      final decodedString = utf8.decode(decodedBytes);
      final Map<String, dynamic> decodedPayload = json.decode(decodedString);

      print('🔵 AUTH_REMOTE_DS: JWT payload decoded: $decodedPayload');

      // Extract user info from the 'sub' (subject) field
      final sub = decodedPayload['sub'];
      if (sub != null && sub is Map) {
        print('🔵 AUTH_REMOTE_DS: User info found in sub: $sub');
        return {
          'id': sub['id'] ?? '',
          'role': sub['role'] ?? 0,
        };
      }

      // Fallback: try to get user info from top level
      return {
        'id': decodedPayload['userId'] ?? decodedPayload['id'] ?? '',
        'role': decodedPayload['role'] ?? 0,
      };
    } catch (e) {
      print('🔴 AUTH_REMOTE_DS: Error decoding JWT token: $e');
      // Return default values if JWT decoding fails
      return {
        'id': 'unknown',
        'role': 0,
      };
    }
  }

  @override
  Future<UserModel> register({
    required String firstName,
    required String lastName,
    required String email,
    required String password,
    String? referralCode,
  }) async {
    print('🔵 AUTH_REMOTE_DS: Starting registration for email: $email');
    print(
        '🔵 AUTH_REMOTE_DS: Registration data: {firstName: $firstName, lastName: $lastName, email: $email, referralCode: $referralCode}');

    try {
      print(
          '🔵 AUTH_REMOTE_DS: Making POST request to ${ApiConstants.register}');

      final requestData = {
        'firstName': firstName,
        'lastName': lastName,
        'email': email,
        'password': password,
        if (referralCode != null) 'ref': referralCode,
      };

      print(
          '🔵 AUTH_REMOTE_DS: Request data: ${requestData.map((k, v) => MapEntry(k, k == 'password' ? '[HIDDEN]' : v))}');

      final response = await client.post(
        ApiConstants.register,
        data: requestData,
      );

      print(
          '🔵 AUTH_REMOTE_DS: Registration response received - Status: ${response.statusCode}');
      print('🔵 AUTH_REMOTE_DS: Response data: ${response.data}');

      if (response.statusCode == 200) {
        final data = response.data;

        print('🔵 AUTH_REMOTE_DS: Checking registration response structure...');
        print('🔵 AUTH_REMOTE_DS: Has user: ${data['user'] != null}');
        print('🔵 AUTH_REMOTE_DS: Has message: ${data['message'] != null}');
        print('🔵 AUTH_REMOTE_DS: Message: ${data['message']}');

        // Check if email verification is required
        if (data['user'] == null && data['message'] != null) {
          print(
              '🔴 AUTH_REMOTE_DS: Email verification required: ${data['message']}');
          throw AuthException(data['message']);
        }

        print(
            '🟢 AUTH_REMOTE_DS: Registration successful, creating UserModel from: ${data['user']}');
        return UserModel.fromJson(data['user']);
      } else {
        print(
            '🔴 AUTH_REMOTE_DS: Registration failed with status: ${response.statusCode}');
        throw ServerException('Registration failed');
      }
    } on DioException catch (e) {
      print('🔴 AUTH_REMOTE_DS: Registration DioException caught');
      print('🔴 AUTH_REMOTE_DS: Error type: ${e.type}');
      print('🔴 AUTH_REMOTE_DS: Error message: ${e.message}');
      print('🔴 AUTH_REMOTE_DS: Response status: ${e.response?.statusCode}');
      print('🔴 AUTH_REMOTE_DS: Response data: ${e.response?.data}');
      throw _handleDioException(e);
    } catch (e) {
      print('🔴 AUTH_REMOTE_DS: Registration general exception caught: $e');
      if (e is AuthException) {
        print('🔴 AUTH_REMOTE_DS: Re-throwing AuthException');
        rethrow;
      }
      throw ServerException('Unexpected error during registration');
    }
  }

  @override
  Future<void> logout() async {
    print('🔵 AUTH_REMOTE_DS: Starting logout process');

    try {
      print('🔵 AUTH_REMOTE_DS: Making POST request to ${ApiConstants.logout}');
      await client.post(ApiConstants.logout);
      print('🟢 AUTH_REMOTE_DS: Logout API call successful');
    } on DioException catch (e) {
      print('🔴 AUTH_REMOTE_DS: Logout API failed with DioException');
      print('🔴 AUTH_REMOTE_DS: Error type: ${e.type}');
      print('🔴 AUTH_REMOTE_DS: Error message: ${e.message}');
      print('🔴 AUTH_REMOTE_DS: Response status: ${e.response?.statusCode}');
      print('🔴 AUTH_REMOTE_DS: Response data: ${e.response?.data}');

      // If logout fails due to authentication issues (401), we still want to clear local data
      if (e.response?.statusCode == 401) {
        print(
            '🟡 AUTH_REMOTE_DS: Logout failed due to authentication, but continuing with local cleanup');
        // Don't throw exception for 401 - just continue with local cleanup
      } else {
        // For other errors, still continue but log them
        print(
            '🟡 AUTH_REMOTE_DS: Logout API failed, but continuing with local cleanup');
      }
    } catch (e) {
      print('🔴 AUTH_REMOTE_DS: Logout general exception: $e');
      print('🟡 AUTH_REMOTE_DS: Continuing with local cleanup despite error');
    }

    // Always clear local tokens regardless of API response
    print('🔵 AUTH_REMOTE_DS: Clearing local tokens');
    clearTokens();
    print('🟢 AUTH_REMOTE_DS: Logout process completed');
  }

  @override
  Future<UserModel> verifyTwoFactor(
      {required String userId, required String code}) async {
    try {
      final response = await client.post(
        ApiConstants.twoFactorAuth,
        data: {
          'userId': userId,
          'code': code,
        },
      );

      if (response.statusCode == 200) {
        final data = response.data;
        return UserModel.fromJson(data['user']);
      } else {
        throw ServerException('2FA verification failed');
      }
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during 2FA verification');
    }
  }

  @override
  Future<void> refreshToken() async {
    try {
      await client.post(ApiConstants.refreshToken);
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during token refresh');
    }
  }

  @override
  Future<void> requestPasswordReset({required String email}) async {
    print(
        '🔵 AUTH_REMOTE_DS: Starting password reset request for email: $email');

    try {
      print(
          '🔵 AUTH_REMOTE_DS: Making POST request to ${ApiConstants.forgotPassword}');

      final response = await client.post(
        ApiConstants.forgotPassword,
        data: {'email': email},
      );

      print(
          '🔵 AUTH_REMOTE_DS: Password reset response - Status: ${response.statusCode}');
      print('🔵 AUTH_REMOTE_DS: Response data: ${response.data}');
      print('🟢 AUTH_REMOTE_DS: Password reset request successful');
    } on DioException catch (e) {
      print('🔴 AUTH_REMOTE_DS: Password reset DioException caught');
      print('🔴 AUTH_REMOTE_DS: Error type: ${e.type}');
      print('🔴 AUTH_REMOTE_DS: Error message: ${e.message}');
      print('🔴 AUTH_REMOTE_DS: Response status: ${e.response?.statusCode}');
      print('🔴 AUTH_REMOTE_DS: Response data: ${e.response?.data}');
      throw _handleDioException(e);
    } catch (e) {
      print('🔴 AUTH_REMOTE_DS: Password reset general exception: $e');
      throw ServerException('Unexpected error during password reset request');
    }
  }

  @override
  Future<void> resetPassword(
      {required String token, required String newPassword}) async {
    try {
      await client.post(
        ApiConstants.resetPassword,
        data: {
          'token': token,
          'password': newPassword,
        },
      );
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during password reset');
    }
  }

  @override
  Future<void> changePassword(
      {required String currentPassword, required String newPassword}) async {
    try {
      await client.post(
        ApiConstants.changePassword,
        data: {
          'currentPassword': currentPassword,
          'newPassword': newPassword,
        },
      );
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during password change');
    }
  }

  @override
  Future<void> verifyEmail({required String token}) async {
    try {
      await client.post(
        ApiConstants.verifyEmail,
        data: {'token': token},
      );
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during email verification');
    }
  }

  @override
  Future<void> resendEmailVerification() async {
    try {
      await client.post(
        '${ApiConstants.verifyEmail}/resend',
      );
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException(
          'Unexpected error during email verification resend');
    }
  }

  @override
  Future<UserModel> googleSignIn({required String idToken}) async {
    try {
      final response = await client.post(
        '${ApiConstants.login}/google',
        data: {'token': idToken},
      );

      if (response.statusCode == 200) {
        final data = response.data;
        return UserModel.fromJson(data['user']);
      } else {
        throw ServerException('Google sign in failed');
      }
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during Google sign in');
    }
  }

  @override
  Future<Map<String, dynamic>> enableTwoFactor({required String type}) async {
    try {
      final response = await client.post(
        '${ApiConstants.twoFactorAuth}/enable',
        data: {'type': type},
      );

      if (response.statusCode == 200) {
        return response.data;
      } else {
        throw ServerException('2FA enable failed');
      }
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during 2FA enable');
    }
  }

  @override
  Future<void> disableTwoFactor({required String code}) async {
    try {
      await client.post(
        '${ApiConstants.twoFactorAuth}/disable',
        data: {'code': code},
      );
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during 2FA disable');
    }
  }

  @override
  Future<UserModel> updateProfile({
    String? firstName,
    String? lastName,
    String? phone,
    String? avatar,
  }) async {
    try {
      final data = <String, dynamic>{};
      if (firstName != null) data['firstName'] = firstName;
      if (lastName != null) data['lastName'] = lastName;
      if (phone != null) data['phone'] = phone;
      if (avatar != null) data['avatar'] = avatar;

      final response = await client.put(
        ApiConstants.updateProfile,
        data: data,
      );

      if (response.statusCode == 200) {
        final responseData = response.data;
        return UserModel.fromJson(responseData['user']);
      } else {
        throw ServerException('Profile update failed');
      }
    } on DioException catch (e) {
      throw _handleDioException(e);
    } catch (e) {
      throw ServerException('Unexpected error during profile update');
    }
  }

  Exception _handleDioException(DioException e) {
    switch (e.response?.statusCode) {
      case 400:
        return BadRequestException(
          e.response?.data?['message'] ?? 'Bad request',
        );
      case 401:
        return UnauthorizedException(
          e.response?.data?['message'] ?? 'Unauthorized',
        );
      case 403:
        return ForbiddenException(
          e.response?.data?['message'] ?? 'Forbidden',
        );
      case 404:
        return NotFoundException(
          e.response?.data?['message'] ?? 'Not found',
        );
      case 422:
        return ValidationException(
          e.response?.data?['message'] ?? 'Validation failed',
          e.response?.data?['errors'],
        );
      case 500:
        return ServerException(
          e.response?.data?['message'] ?? 'Internal server error',
        );
      default:
        if (e.type == DioExceptionType.connectionTimeout ||
            e.type == DioExceptionType.receiveTimeout ||
            e.type == DioExceptionType.sendTimeout) {
          return TimeoutException('Request timeout');
        }
        if (e.type == DioExceptionType.connectionError) {
          return ConnectionException('No internet connection');
        }
        return NetworkException('Network error');
    }
  }
}
