import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import '../../../../../core/constants/api_constants.dart';
import '../../../../../core/network/api_client.dart';
import '../../../../../core/errors/exceptions.dart';
import '../models/p2p_trade_model.dart';

abstract class P2PRemoteDataSource {
  // Offers
  Future<Map<String, dynamic>> getOffers({
    String? type,
    String? currency,
    String? walletType,
    double? amount,
    String? paymentMethod,
    String? location,
    String? sortField,
    String? sortOrder,
    int? page,
    int? perPage,
  });

  Future<Map<String, dynamic>> createOffer(Map<String, dynamic> offerData);
  Future<Map<String, dynamic>> getOfferById(String id);
  Future<Map<String, dynamic>> updateOffer(
      String id, Map<String, dynamic> data);
  Future<void> deleteOffer(String id);
  Future<List<Map<String, dynamic>>> getPopularOffers({String? currency});

  // Trades
  Future<Map<String, dynamic>> getTrades({
    String? status,
    String? type,
    int? page,
    int? perPage,
  });

  Future<Map<String, dynamic>> getTradeById(String id);
  Future<P2PTradeModel> createTrade({
    required String offerId,
    required double amount,
    required String paymentMethodId,
    String? notes,
  });
  Future<P2PTradeModel> confirmTrade(String tradeId);
  Future<P2PTradeModel> cancelTrade(String tradeId, String reason);
  Future<P2PTradeModel> releaseTrade(String tradeId);
  Future<void> disputeTrade(String tradeId, String reason, String description);
  Future<Map<String, dynamic>> reviewTrade(
      String id, Map<String, dynamic> review);

  // Payment Methods
  Future<List<Map<String, dynamic>>> getPaymentMethods();
  Future<Map<String, dynamic>> createPaymentMethod(Map<String, dynamic> data);
  Future<Map<String, dynamic>> updatePaymentMethod(
      String id, Map<String, dynamic> data);
  Future<void> deletePaymentMethod(String id);

  // Market Data
  Future<Map<String, dynamic>> getMarketStats();
  Future<List<Map<String, dynamic>>> getTopMarkets();
  Future<List<Map<String, dynamic>>> getMarketHighlights();

  // Dashboard
  Future<Map<String, dynamic>> getDashboardData();
  Future<Map<String, dynamic>> getDashboardStats();
  Future<List<Map<String, dynamic>>> getTradingActivity({
    int limit = 10,
    int offset = 0,
    String? type,
  });
  Future<Map<String, dynamic>> getPortfolioData();

  // Reviews
  Future<Map<String, dynamic>> getReviews({
    String? reviewerId,
    String? revieweeId,
    String? tradeId,
    double? minRating,
    double? maxRating,
    int page = 1,
    int perPage = 20,
    String sortBy = 'createdAt',
    String sortOrder = 'desc',
  });
  Future<Map<String, dynamic>> getUserReviews({
    required String userId,
    bool includeGiven = true,
    bool includeReceived = true,
    int limit = 20,
  });

  // Guided Matching
  Future<Map<String, dynamic>> submitGuidedMatching(
      Map<String, dynamic> criteria);
  Future<Map<String, dynamic>> findMatches(Map<String, dynamic> criteria);
  Future<Map<String, dynamic>> comparePrices(Map<String, dynamic> criteria);
}

@Injectable(as: P2PRemoteDataSource)
class P2PRemoteDataSourceImpl implements P2PRemoteDataSource {
  final ApiClient _apiClient;

  P2PRemoteDataSourceImpl(this._apiClient);

  @override
  Future<Map<String, dynamic>> getOffers({
    String? type,
    String? currency,
    String? walletType,
    double? amount,
    String? paymentMethod,
    String? location,
    String? sortField,
    String? sortOrder,
    int? page,
    int? perPage,
  }) async {
    try {
      final queryParams = <String, dynamic>{};

      if (type != null) queryParams['type'] = type;
      if (currency != null) queryParams['currency'] = currency;
      if (walletType != null) queryParams['walletType'] = walletType;
      if (amount != null) queryParams['amount'] = amount.toString();
      if (paymentMethod != null) queryParams['paymentMethod'] = paymentMethod;
      if (location != null) queryParams['location'] = location;
      if (sortField != null) queryParams['sortField'] = sortField;
      if (sortOrder != null) queryParams['sortOrder'] = sortOrder;
      if (page != null) queryParams['page'] = page.toString();
      if (perPage != null) queryParams['perPage'] = perPage.toString();

      final response = await _apiClient.get(
        ApiConstants.p2pOffers,
        queryParameters: queryParams,
      );

      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get offers',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> createOffer(
      Map<String, dynamic> offerData) async {
    try {
      print('🌐 REMOTE DATA SOURCE: createOffer called');
      print('🎯 REMOTE DATA SOURCE: Endpoint: ${ApiConstants.p2pCreateOffer}');
      print('📦 REMOTE DATA SOURCE: Payload being sent:');
      print('${JsonEncoder.withIndent('  ').convert(offerData)}');

      print('🔄 REMOTE DATA SOURCE: Making POST request...');
      final response = await _apiClient.post(
        ApiConstants.p2pCreateOffer,
        data: offerData,
      );

      print('📨 REMOTE DATA SOURCE: Response received');
      print('📊 REMOTE DATA SOURCE: Status Code: ${response.statusCode}');
      print('📋 REMOTE DATA SOURCE: Response Data:');
      print('${JsonEncoder.withIndent('  ').convert(response.data)}');

      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      print('💥 REMOTE DATA SOURCE: DioException occurred');
      print('📊 REMOTE DATA SOURCE: Status Code: ${e.response?.statusCode}');
      print('📋 REMOTE DATA SOURCE: Error Response:');
      print('${e.response?.data}');
      print('🔍 REMOTE DATA SOURCE: Error Message: ${e.message}');

      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to create offer',
      );
    } catch (e) {
      print('💥 REMOTE DATA SOURCE: Unexpected error - ${e.toString()}');
      print('🔍 REMOTE DATA SOURCE: Error type: ${e.runtimeType}');
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getOfferById(String id) async {
    try {
      final response = await _apiClient.get('${ApiConstants.p2pOfferById}/$id');
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get offer',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> updateOffer(
      String id, Map<String, dynamic> data) async {
    try {
      final response = await _apiClient
          .put('${ApiConstants.p2pUpdateOffer}/$id', data: data);
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to update offer',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> deleteOffer(String id) async {
    try {
      await _apiClient.delete('${ApiConstants.p2pDeleteOffer}/$id');
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to delete offer',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getPopularOffers(
      {String? currency}) async {
    try {
      final queryParams = <String, dynamic>{};
      if (currency != null) queryParams['currency'] = currency;

      final response = await _apiClient.get(
        ApiConstants.p2pPopularOffers,
        queryParameters: queryParams,
      );

      final data = response.data;
      if (data is List) {
        return data.cast<Map<String, dynamic>>();
      } else if (data is Map && data['data'] is List) {
        return (data['data'] as List).cast<Map<String, dynamic>>();
      }
      return [];
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get popular offers',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getTrades({
    String? status,
    String? type,
    int? page,
    int? perPage,
  }) async {
    try {
      final queryParams = <String, dynamic>{};
      if (status != null) queryParams['status'] = status;
      if (type != null) queryParams['type'] = type;
      if (page != null) queryParams['page'] = page.toString();
      if (perPage != null) queryParams['perPage'] = perPage.toString();

      final response = await _apiClient.get(
        ApiConstants.p2pTrades,
        queryParameters: queryParams,
      );

      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get trades',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getTradeById(String id) async {
    try {
      final response = await _apiClient.get('${ApiConstants.p2pTradeById}/$id');
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get trade',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<P2PTradeModel> createTrade({
    required String offerId,
    required double amount,
    required String paymentMethodId,
    String? notes,
  }) async {
    try {
      // Based on v5 frontend pattern: POST /api/trades
      // Since this endpoint doesn't exist in v5 backend, using P2P pattern
      final response = await _apiClient.post(
        '/p2p/trade',
        data: {
          'offerId': offerId,
          'amount': amount,
          'paymentMethodId': paymentMethodId,
          if (notes != null) 'notes': notes,
        },
      );

      return P2PTradeModel.fromJson(response.data);
    } catch (e) {
      throw ServerException('Failed to create trade: ${e.toString()}');
    }
  }

  @override
  Future<P2PTradeModel> confirmTrade(String tradeId) async {
    try {
      // This matches the actual v5 backend endpoint
      final response = await _apiClient.post('/p2p/trade/$tradeId/confirm');
      return P2PTradeModel.fromJson(response.data);
    } catch (e) {
      throw ServerException('Failed to confirm trade: ${e.toString()}');
    }
  }

  @override
  Future<P2PTradeModel> cancelTrade(String tradeId, String reason) async {
    try {
      // This matches the actual v5 backend endpoint
      final response = await _apiClient.post(
        '/p2p/trade/$tradeId/cancel',
        data: {'reason': reason},
      );
      return P2PTradeModel.fromJson(response.data);
    } catch (e) {
      throw ServerException('Failed to cancel trade: ${e.toString()}');
    }
  }

  @override
  Future<P2PTradeModel> releaseTrade(String tradeId) async {
    try {
      // This matches the actual v5 backend endpoint
      final response = await _apiClient.post('/p2p/trade/$tradeId/release');
      return P2PTradeModel.fromJson(response.data);
    } catch (e) {
      throw ServerException('Failed to release trade: ${e.toString()}');
    }
  }

  @override
  Future<void> disputeTrade(
      String tradeId, String reason, String description) async {
    try {
      // This matches the actual v5 backend endpoint
      await _apiClient.post(
        '/p2p/trade/$tradeId/dispute',
        data: {
          'reason': reason,
          'description': description,
        },
      );
    } catch (e) {
      throw ServerException('Failed to dispute trade: ${e.toString()}');
    }
  }

  @override
  Future<Map<String, dynamic>> reviewTrade(
      String id, Map<String, dynamic> review) async {
    try {
      final response = await _apiClient.post(
        '${ApiConstants.p2pReviewTrade}/$id/review',
        data: review,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to review trade',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getPaymentMethods() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pPaymentMethods);

      final data = response.data;
      if (data is List) {
        return data.cast<Map<String, dynamic>>();
      } else if (data is Map && data['data'] is List) {
        return (data['data'] as List).cast<Map<String, dynamic>>();
      }
      return [];
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get payment methods',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> createPaymentMethod(
      Map<String, dynamic> data) async {
    try {
      final response = await _apiClient.post(
        ApiConstants.p2pCreatePaymentMethod,
        data: data,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to create payment method',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> updatePaymentMethod(
      String id, Map<String, dynamic> data) async {
    try {
      final response = await _apiClient.put(
        '${ApiConstants.p2pUpdatePaymentMethod}/$id',
        data: data,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to update payment method',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> deletePaymentMethod(String id) async {
    try {
      await _apiClient.delete('${ApiConstants.p2pDeletePaymentMethod}/$id');
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to delete payment method',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getMarketStats() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pMarketStats);
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get market stats',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getTopMarkets() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pMarketTop);

      final data = response.data;
      if (data is List) {
        return data.cast<Map<String, dynamic>>();
      } else if (data is Map && data['data'] is List) {
        return (data['data'] as List).cast<Map<String, dynamic>>();
      }
      return [];
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get top markets',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getMarketHighlights() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pMarketHighlights);

      final data = response.data;
      if (data is List) {
        return data.cast<Map<String, dynamic>>();
      } else if (data is Map && data['data'] is List) {
        return (data['data'] as List).cast<Map<String, dynamic>>();
      }
      return [];
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get market highlights',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> submitGuidedMatching(
      Map<String, dynamic> criteria) async {
    try {
      final response = await _apiClient.post(
        ApiConstants.p2pGuidedMatching,
        data: criteria,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to submit guided matching',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getDashboardData() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pDashboardData);
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get dashboard data',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getDashboardStats() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pDashboardStats);
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get dashboard stats',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getTradingActivity({
    int limit = 10,
    int offset = 0,
    String? type,
  }) async {
    try {
      final queryParams = <String, dynamic>{
        'limit': limit.toString(),
        'offset': offset.toString(),
      };
      if (type != null) queryParams['type'] = type;

      final response = await _apiClient.get(
        ApiConstants.p2pDashboardActivity,
        queryParameters: queryParams,
      );

      final data = response.data;
      if (data is List) {
        return data.cast<Map<String, dynamic>>();
      } else if (data is Map && data['data'] is List) {
        return (data['data'] as List).cast<Map<String, dynamic>>();
      }
      return [];
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get trading activity',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getPortfolioData() async {
    try {
      final response = await _apiClient.get(ApiConstants.p2pDashboardPortfolio);
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get portfolio data',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getReviews({
    String? reviewerId,
    String? revieweeId,
    String? tradeId,
    double? minRating,
    double? maxRating,
    int page = 1,
    int perPage = 20,
    String sortBy = 'createdAt',
    String sortOrder = 'desc',
  }) async {
    try {
      final queryParams = <String, dynamic>{
        'page': page.toString(),
        'perPage': perPage.toString(),
        'sortBy': sortBy,
        'sortOrder': sortOrder,
      };

      if (reviewerId != null) queryParams['reviewerId'] = reviewerId;
      if (revieweeId != null) queryParams['revieweeId'] = revieweeId;
      if (tradeId != null) queryParams['tradeId'] = tradeId;
      if (minRating != null) queryParams['minRating'] = minRating.toString();
      if (maxRating != null) queryParams['maxRating'] = maxRating.toString();

      final response = await _apiClient.get(
        ApiConstants.p2pReviews,
        queryParameters: queryParams,
      );

      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get reviews',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> getUserReviews({
    required String userId,
    bool includeGiven = true,
    bool includeReceived = true,
    int limit = 20,
  }) async {
    try {
      final queryParams = <String, dynamic>{
        'userId': userId,
        'includeGiven': includeGiven.toString(),
        'includeReceived': includeReceived.toString(),
        'limit': limit.toString(),
      };

      final response = await _apiClient.get(
        ApiConstants.p2pUserReviews,
        queryParameters: queryParams,
      );

      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to get user reviews',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> findMatches(
      Map<String, dynamic> criteria) async {
    try {
      final response = await _apiClient.post(
        ApiConstants.p2pGuidedMatching,
        data: criteria,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to find matches',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<Map<String, dynamic>> comparePrices(
      Map<String, dynamic> criteria) async {
    try {
      // Using guided matching endpoint for price comparison
      final response = await _apiClient.post(
        '${ApiConstants.p2pGuidedMatching}/compare-prices',
        data: criteria,
      );
      return response.data as Map<String, dynamic>;
    } on DioException catch (e) {
      throw ServerException(
        e.response?.data?['message'] ?? 'Failed to compare prices',
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }
}
