import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/network/dio_client.dart';
import '../../../../core/constants/api_constants.dart';
import '../../../../core/errors/exceptions.dart';
import '../models/transfer_request_model.dart';
import '../models/transfer_response_model.dart';
import '../models/transfer_option_model.dart';
import '../models/currency_option_model.dart';
import 'transfer_remote_datasource.dart';

@Injectable(as: TransferRemoteDataSource)
class TransferRemoteDataSourceImpl implements TransferRemoteDataSource {
  final DioClient _dioClient;

  const TransferRemoteDataSourceImpl(this._dioClient);

  @override
  Future<List<TransferOptionModel>> getTransferOptions() async {
    try {
      final response = await _dioClient.get(ApiConstants.transferOptions);

      // Response structure: { "types": [{"id": "FIAT", "name": "Fiat"}, ...] }
      final List<dynamic> types = response.data['types'] as List<dynamic>;

      return types
          .map((json) =>
              TransferOptionModel.fromJson(json as Map<String, dynamic>))
          .toList();
    } on DioException catch (e) {
      throw Exception('Failed to fetch transfer options: ${e.message}');
    }
  }

  @override
  Future<List<CurrencyOptionModel>> getCurrencies({
    required String walletType,
    String? targetWalletType,
  }) async {
    try {
      final Map<String, dynamic> queryParams = {
        'action': 'transfer',
        'walletType': walletType,
      };

      if (targetWalletType != null) {
        queryParams['targetWalletType'] = targetWalletType;
      }

      final response = await _dioClient.get(
        ApiConstants.transferCurrency,
        queryParameters: queryParams,
      );

      // The API always returns: { "from": [...], "to": [...] }
      final data = response.data;

      if (targetWalletType != null) {
        // For wallet-to-wallet transfers, return 'to' currencies (target currencies)
        final List<dynamic> toCurrencies = data['to'] as List<dynamic>;
        return toCurrencies
            .map((json) =>
                CurrencyOptionModel.fromJson(json as Map<String, dynamic>))
            .toList();
      } else {
        // For source wallet selection, return 'from' currencies (source currencies)
        final List<dynamic> fromCurrencies = data['from'] as List<dynamic>;
        return fromCurrencies
            .map((json) =>
                CurrencyOptionModel.fromJson(json as Map<String, dynamic>))
            .toList();
      }
    } on DioException catch (e) {
      throw Exception('Failed to fetch currencies: ${e.message}');
    }
  }

  @override
  Future<List<CurrencyOptionModel>> getWalletBalance({
    required String walletType,
  }) async {
    try {
      final response = await _dioClient.get(
        ApiConstants.transferCurrency,
        queryParameters: {
          'action': 'transfer',
          'walletType': walletType,
        },
      );

      // The API always returns: { "from": [...], "to": [...] }
      final data = response.data;
      final List<dynamic> fromCurrencies = data['from'] as List<dynamic>;

      return fromCurrencies
          .map((json) =>
              CurrencyOptionModel.fromJson(json as Map<String, dynamic>))
          .toList();
    } on DioException catch (e) {
      throw Exception('Failed to fetch wallet balance: ${e.message}');
    }
  }

  @override
  Future<TransferResponseModel> createTransfer(
    TransferRequestModel request,
  ) async {
    try {
      // Validate required fields before making the API call
      if (request.toType == null) {
        throw Exception('toType is required for transfer');
      }

      final Map<String, dynamic> requestBody = {
        'fromType': request.fromType,
        'toType': request.toType!,
        'fromCurrency': request.fromCurrency,
        'toCurrency': request.toCurrency ?? request.fromCurrency,
        'amount': request.amount,
        'transferType': request.transferType,
      };

      // Add clientId for client transfers
      if (request.transferType == 'client' && request.clientId != null) {
        requestBody['clientId'] = request.clientId;
      }

      final response =
          await _dioClient.post('/api/finance/transfer', data: requestBody);

      return TransferResponseModel.fromJson(response.data);
    } on DioException catch (e) {
      if (e.response?.statusCode == 400) {
        throw ServerException(
          e.response?.data?['message'] ?? 'Invalid transfer request',
        );
      } else if (e.response?.statusCode == 401) {
        throw AuthException('Authentication required');
      } else if (e.response?.statusCode == 403) {
        throw AuthException('Insufficient permissions');
      } else {
        throw ServerException(
          e.response?.data?['message'] ?? 'Unexpected error occurred',
        );
      }
    } catch (e) {
      throw ServerException('Unexpected error occurred');
    }
  }
}
