import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/network/dio_client.dart';
import '../models/deposit_gateway_model.dart';
import '../models/deposit_method_model.dart';
import '../models/deposit_transaction_model.dart';
import '../models/currency_option_model.dart';

abstract class DepositRemoteDataSource {
  Future<List<CurrencyOptionModel>> fetchCurrencyOptions(String walletType);
  Future<Map<String, dynamic>> fetchDepositMethods(String currency);
  Future<DepositTransactionModel> createFiatDeposit({
    required String methodId,
    required double amount,
    required String currency,
    required Map<String, dynamic> customFields,
  });
  Future<Map<String, dynamic>> createStripePaymentIntent({
    required double amount,
    required String currency,
  });
  Future<DepositTransactionModel> verifyStripePayment({
    required String paymentIntentId,
  });

  // PayPal deposit methods
  Future<Map<String, dynamic>> createPayPalOrder({
    required double amount,
    required String currency,
  });

  Future<DepositTransactionModel> verifyPayPalPayment({
    required String orderId,
  });
}

@Injectable(as: DepositRemoteDataSource)
class DepositRemoteDataSourceImpl implements DepositRemoteDataSource {
  const DepositRemoteDataSourceImpl(this._dioClient);

  final DioClient _dioClient;

  @override
  Future<List<CurrencyOptionModel>> fetchCurrencyOptions(
      String walletType) async {
    print('🔵 DEPOSIT_REMOTE_DS: Fetching currency options for $walletType');

    try {
      final response = await _dioClient.get(
        '/api/finance/currency',
        queryParameters: {
          'action': 'deposit',
          'walletType': walletType,
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: Currency options response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: Currency options response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as List<dynamic>;
        final currencyOptions = data
            .map((json) =>
                CurrencyOptionModel.fromJson(json as Map<String, dynamic>))
            .toList();

        print(
            '🟢 DEPOSIT_REMOTE_DS: Found ${currencyOptions.length} currency options');
        return currencyOptions;
      } else {
        throw Exception(
            'Failed to fetch currency options: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: DioException: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');
      throw Exception('Network error: ${e.message}');
    } catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: Unexpected error: $e');
      throw Exception('Failed to fetch currency options: $e');
    }
  }

  @override
  Future<Map<String, dynamic>> fetchDepositMethods(String currency) async {
    print('🔵 DEPOSIT_REMOTE_DS: Fetching deposit methods for $currency');

    try {
      final response = await _dioClient.get(
        '/api/finance/currency/FIAT/$currency',
        queryParameters: {'action': 'deposit'},
      );

      print('🔵 DEPOSIT_REMOTE_DS: Response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: Response data keys: ${response.data?.keys.toList()}');
      print('🔵 DEPOSIT_REMOTE_DS: Full response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;

        // Parse gateways
        final gatewaysData = data['gateways'] as List<dynamic>? ?? [];
        print('🔵 DEPOSIT_REMOTE_DS: Raw gateways data: $gatewaysData');

        final gateways = <DepositGatewayModel>[];
        for (var i = 0; i < gatewaysData.length; i++) {
          try {
            final gateway = DepositGatewayModel.fromJson(
                gatewaysData[i] as Map<String, dynamic>);
            gateways.add(gateway);
            print(
                '🟢 DEPOSIT_REMOTE_DS: Successfully parsed gateway ${i + 1}: ${gateway.name}');
          } catch (e) {
            print('🔴 DEPOSIT_REMOTE_DS: Error parsing gateway ${i + 1}: $e');
            print('🔴 DEPOSIT_REMOTE_DS: Gateway data: ${gatewaysData[i]}');
          }
        }

        // Parse methods
        final methodsData = data['methods'] as List<dynamic>? ?? [];
        print('🔵 DEPOSIT_REMOTE_DS: Raw methods data: $methodsData');

        final methods = <DepositMethodModel>[];
        for (var i = 0; i < methodsData.length; i++) {
          try {
            final method = DepositMethodModel.fromJson(
                methodsData[i] as Map<String, dynamic>);
            methods.add(method);
            print(
                '🟢 DEPOSIT_REMOTE_DS: Successfully parsed method ${i + 1}: ${method.title}');
          } catch (e) {
            print('🔴 DEPOSIT_REMOTE_DS: Error parsing method ${i + 1}: $e');
            print('🔴 DEPOSIT_REMOTE_DS: Method data: ${methodsData[i]}');
          }
        }

        print(
            '🟢 DEPOSIT_REMOTE_DS: Found ${gateways.length} gateways and ${methods.length} methods');

        return {
          'gateways': gateways,
          'methods': methods,
        };
      } else {
        throw Exception(
            'Failed to fetch deposit methods: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: DioException: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');
      throw Exception('Network error: ${e.message}');
    } catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: Unexpected error: $e');
      print('🔴 DEPOSIT_REMOTE_DS: Stack trace: ${StackTrace.current}');
      throw Exception('Failed to fetch deposit methods: $e');
    }
  }

  @override
  Future<DepositTransactionModel> createFiatDeposit({
    required String methodId,
    required double amount,
    required String currency,
    required Map<String, dynamic> customFields,
  }) async {
    print('🔵 DEPOSIT_REMOTE_DS: Creating FIAT deposit');
    print(
        '🔵 DEPOSIT_REMOTE_DS: Method: $methodId, Amount: $amount, Currency: $currency');

    try {
      final response = await _dioClient.post(
        '/api/finance/deposit/fiat',
        data: {
          'methodId': methodId,
          'amount': amount,
          'currency': currency,
          'customFields': customFields,
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: Create deposit response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: Create deposit response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;
        final transactionData = data['transaction'] as Map<String, dynamic>;

        // Add additional fields from response
        transactionData['currency'] = data['currency'] ?? currency;
        transactionData['method'] = data['method'] ?? 'Unknown';

        final transaction = DepositTransactionModel.fromJson(transactionData);
        print(
            '🟢 DEPOSIT_REMOTE_DS: Successfully created deposit transaction: ${transaction.id}');

        return transaction;
      } else {
        throw Exception('Failed to create deposit: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: DioException creating deposit: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');

      // Extract error message from response if available
      final errorMessage = e.response?.data?['message'] ?? e.message;
      throw Exception('Deposit failed: $errorMessage');
    } catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: Unexpected error creating deposit: $e');
      throw Exception('Failed to create deposit: $e');
    }
  }

  @override
  Future<Map<String, dynamic>> createStripePaymentIntent({
    required double amount,
    required String currency,
  }) async {
    print(
        '🔵 DEPOSIT_REMOTE_DS: Creating Stripe payment intent for $amount $currency');

    try {
      final response = await _dioClient.post(
        '/api/finance/deposit/fiat/stripe',
        data: {
          'amount': amount,
          'currency': currency,
          'intent': true, // This is crucial for Flutter/mobile
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: Stripe payment intent response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: Stripe payment intent response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;

        if (data.containsKey('id') && data.containsKey('clientSecret')) {
          print(
              '🟢 DEPOSIT_REMOTE_DS: Stripe payment intent created successfully');
          return data;
        } else {
          throw Exception(
              'Invalid Stripe response: missing id or clientSecret');
        }
      } else {
        throw Exception(
            'Failed to create Stripe payment intent: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: DioException creating Stripe payment intent: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');
      throw Exception('Network error: ${e.message}');
    } catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: Unexpected error creating Stripe payment intent: $e');
      throw Exception('Failed to create Stripe payment intent: $e');
    }
  }

  @override
  Future<DepositTransactionModel> verifyStripePayment({
    required String paymentIntentId,
  }) async {
    print(
        '🔵 DEPOSIT_REMOTE_DS: Verifying Stripe payment intent: $paymentIntentId');

    try {
      final response = await _dioClient.post(
        '/api/finance/deposit/fiat/stripe/verify-intent',
        queryParameters: {
          'intentId': paymentIntentId,
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: Stripe verification response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: Stripe verification response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;

        // Handle both new transaction and already processed cases
        if (data['transaction'] != null) {
          final transactionData = data['transaction'] as Map<String, dynamic>;

          // Add additional fields from response if available
          if (data['currency'] != null) {
            transactionData['currency'] = data['currency'];
          }
          if (data['method'] != null) {
            transactionData['method'] = data['method'];
          }

          final transaction = DepositTransactionModel.fromJson(transactionData);
          print(
              '🟢 DEPOSIT_REMOTE_DS: Stripe payment verified successfully - Transaction ID: ${transaction.id}');
          return transaction;
        } else {
          throw Exception(
              'Invalid verification response: missing transaction data');
        }
      } else {
        throw Exception(
            'Failed to verify Stripe payment: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: DioException verifying Stripe payment: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');

      // Extract error message from response if available
      final errorMessage = e.response?.data?['message'] ?? e.message;
      throw Exception('Network error: $errorMessage');
    } catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: Unexpected error verifying Stripe payment: $e');
      throw Exception('Failed to verify payment: $e');
    }
  }

  @override
  Future<Map<String, dynamic>> createPayPalOrder({
    required double amount,
    required String currency,
  }) async {
    print('🔵 DEPOSIT_REMOTE_DS: Creating PayPal order for $amount $currency');

    try {
      final response = await _dioClient.post(
        '/api/finance/deposit/fiat/paypal',
        data: {
          'amount': amount,
          'currency': currency,
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: PayPal order response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: PayPal order response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;

        if (data.containsKey('id') && data.containsKey('links')) {
          print('🟢 DEPOSIT_REMOTE_DS: PayPal order created successfully');
          return data;
        } else {
          throw Exception('Invalid PayPal response: missing id or links');
        }
      } else {
        throw Exception(
            'Failed to create PayPal order: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: DioException creating PayPal order: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');
      throw Exception('Network error: ${e.message}');
    } catch (e) {
      print('🔴 DEPOSIT_REMOTE_DS: Unexpected error creating PayPal order: $e');
      throw Exception('Failed to create PayPal order: $e');
    }
  }

  @override
  Future<DepositTransactionModel> verifyPayPalPayment({
    required String orderId,
  }) async {
    print('🔵 DEPOSIT_REMOTE_DS: Verifying PayPal payment for order: $orderId');

    try {
      final response = await _dioClient.post(
        '/api/finance/deposit/fiat/paypal/verify',
        queryParameters: {
          'orderId': orderId,
        },
      );

      print(
          '🔵 DEPOSIT_REMOTE_DS: PayPal verification response status: ${response.statusCode}');
      print(
          '🔵 DEPOSIT_REMOTE_DS: PayPal verification response data: ${response.data}');

      if (response.statusCode == 200 && response.data != null) {
        final data = response.data as Map<String, dynamic>;

        // The response structure may vary - need to handle different formats
        if (data.containsKey('transaction')) {
          final transactionData = data['transaction'] as Map<String, dynamic>;
          return DepositTransactionModel.fromJson(transactionData);
        } else {
          // Create transaction from verification response data
          return DepositTransactionModel(
            id: data['id']?.toString() ??
                'txn_${DateTime.now().millisecondsSinceEpoch}',
            userId: 'current_user', // Should come from auth context
            walletId: 'wallet_id', // Should come from selected wallet
            type: 'DEPOSIT',
            amount: (data['amount'] as num?)?.toDouble() ?? 0.0,
            status: 'completed',
            currency: data['currency']?.toString() ?? 'USD',
            method: 'PayPal',
            fee: (data['fee'] as num?)?.toDouble() ?? 0.0,
            metadata: {
              'orderId': orderId,
              'method': 'PAYPAL',
            },
            description: 'PayPal payment completed successfully',
            createdAt: DateTime.now(),
          );
        }
      } else {
        throw Exception(
            'Failed to verify PayPal payment: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: DioException verifying PayPal payment: ${e.message}');
      print('🔴 DEPOSIT_REMOTE_DS: Response: ${e.response?.data}');
      throw Exception('Network error: ${e.message}');
    } catch (e) {
      print(
          '🔴 DEPOSIT_REMOTE_DS: Unexpected error verifying PayPal payment: $e');
      throw Exception('Failed to verify PayPal payment: $e');
    }
  }
}
