import 'dart:convert';

import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:payment_plugin/domain/models/payment_configurations.dart';
import 'package:payment_plugin/domain/models/payment_method.dart';
import 'package:payment_plugin/domain/models/stored_payment_method.dart';
import 'package:payment_plugin/data/remote/api/api_client.dart';
import 'package:payment_plugin/common/constants.dart';
import 'package:payment_plugin/utils/json.dart';

class AdyenRepository {
  final ApiClient _api;

  /// Creates an AdyenRepository with a Dio instance from the main app
  ///
  /// [dio] - The Dio instance from your main app (with all configured interceptors, baseUrl, etc.)
  ///
  /// Example:
  /// ```dart
  /// final repo = AdyenRepository(
  ///   dio: yourConfiguredDioInstance,
  /// );
  /// ```
  AdyenRepository({required Dio dio}) : _api = ApiClient(dio);

  Future<Iterable<StoredPaymentMethod>> getCards() async {
    final cards = await _api.getPaymentMethods();
    return cards.storedPaymentMethods ?? [];
  }

  Future<void> removeCard(String cardId) async {
    try {
      await _api.removePaymentMethod(cardId);
    } catch (e) {
      throw Exception(e);
    }
  }

  Future<dynamic> addCard(PaymentMethod paymentMethod) async {
    final response = await _api.storePaymentMethod(paymentMethod);
    return response;
  }

  Future<dynamic> createAdyenSessionForConcierge(int orderId) async {
    final data = {"OrderId": orderId, "ReturnUrl": "comwell://"};
    return _api.createAdyenSessionForConcierge(data);
  }

  Future<Json?> postPaymentsDetails(Json body, String apiKey) async {
    final contentType = "application/json";
    final Map<String, dynamic> data = {
      "shopperReference": "Test reference",
      "amount": {"value:": 0, "currency": "DKK"},
      "countryCode": "DK",
      "merchantAccount": "ComwellHotelsECOM",
      "returnUrl": "comwell://",
      "reference": "flutter-test_${DateTime.now().millisecondsSinceEpoch}",
      "channel": "iOS",
    };
    data.addAll(body);
    data.remove("storePaymentMethod");
    final response = await _api.postPaymentsDetails(data, contentType, apiKey);
    return response;
  }

  Future<Json> submitPayment(
    Json paymentResult,
    String shopperReference,
    String merchantAccount,
    String apiKey,
  ) async {
    final Map<String, dynamic> data = {
      "shopperReference": shopperReference,
      "amount": {"value:": 0, "currency": "DKK"},
      "countryCode": "DK",
      "merchantAccount": merchantAccount,
      "returnUrl": "comwell://",
      "reference": "flutter-test_${DateTime.now().millisecondsSinceEpoch}",
      "channel": "iOS",
    };
    data.addAll(paymentResult);
    data.remove("storePaymentMethod");
    debugPrint("Data: $data");
    final response = await _api.submitPayment(data, apiKey, "application/json");
    return response;
  }

  Future<PaymentConfigurations?> sessionCheckout(
    String hotelCode,
    String bookingId,
    bool usePoints,
  ) async {
    final body = {
      "hotelCode": hotelCode,
      "bookingConfirmationNumber": bookingId,
      "returnUrl": returnUrl,
      "usePoints": usePoints,
    };
    final json = jsonEncode(body);
    final response = await _api.createAdyenSession(json) as Map<String, dynamic>;
    final clientKey = response["clientKey"] as String;
    final sessionResponse = response["sessionResponse"];
    final payedWithPoints = response["isFullyPaidWithPoints"] as bool;
    if (payedWithPoints) {
      return null;
    }
    final id = sessionResponse["id"] as String;
    final sessionData = sessionResponse["sessionData"] as String;
    final availablePaymentMethods =
        await _api.listAvailablePaymentMethods() as Map<String, dynamic>;

    final scheme = _findPaymentMethod(availablePaymentMethods, "scheme");
    final googlePay = _findPaymentMethod(availablePaymentMethods, "googlePay");
    final applePay = _findPaymentMethod(availablePaymentMethods, "applePay");

    // Use the server response amount for consistency across all payment methods
    final serverAmount = Amount(value: sessionResponse["amount"]["value"] as int, currency: "DKK");

    final session = await AdyenCheckout.session.create(
      sessionId: id,
      sessionData: sessionData,
      configuration: dropInConfiguration(serverAmount, clientKey, false),
    );

    return PaymentConfigurations(
      sessionCheckout: session,
      googlePayConfiguration: _getGooglePayComponentConfig(clientKey),
      dropInConfiguration: dropInConfiguration(serverAmount, clientKey, false),
      cardComponentConfiguration: cardComponentConfiguration(serverAmount, clientKey),
      applePayConfiguration: _applePayComponentConfiguration(clientKey, serverAmount, false),
      isFullyPaidWithPoints: payedWithPoints,
      availablePaymentMethods: [scheme!, googlePay!, applePay!],
    );
  }

  Future<PaymentConfigurations> createSession(
    String sessionId,
    String clientKey,
    String sessionData,
  ) async {
    final amount = Amount(value: 123, currency: "DKK");
    final session = await AdyenCheckout.session.create(
      sessionData: sessionData,
      sessionId: sessionId,
      configuration: dropInConfiguration(amount, clientKey, false),
    );

    final availablePaymentMethods =
        await _api.listAvailablePaymentMethods() as Map<String, dynamic>;

    final scheme = _findPaymentMethod(availablePaymentMethods, "scheme");
    final googlePay = _findPaymentMethod(availablePaymentMethods, "googlePay");
    final applePay = _findPaymentMethod(availablePaymentMethods, "applePay");
    return PaymentConfigurations(
      sessionCheckout: session,
      dropInConfiguration: dropInConfiguration(amount, clientKey, false),
      googlePayConfiguration: _getGooglePayComponentConfig(clientKey),
      cardComponentConfiguration: cardComponentConfiguration(amount, clientKey),
      applePayConfiguration: _applePayComponentConfiguration(clientKey, amount, false),
      isFullyPaidWithPoints: false,
      availablePaymentMethods: [scheme!, googlePay!, applePay!],
    );
  }

  Future<PaymentConfigurations?> fetchSessionForAddingCard() async {
    final body = {"returnUrl": returnUrl};
    final json = jsonEncode(body);
    final response = await _api.createAdyenSessionForCards(json) as Map<String, dynamic>;
    final availablePaymentMethods =
        await _api.listAvailablePaymentMethods() as Map<String, dynamic>;

    final clientKey = response["clientKey"] as String;
    final sessionResponse = response["sessionResponse"];
    final id = sessionResponse["id"] as String;
    final sessionData = sessionResponse["sessionData"] as String;

    final scheme = _findPaymentMethod(availablePaymentMethods, "scheme");
    final googlePay = _findPaymentMethod(availablePaymentMethods, "googlePay");
    final applePay = _findPaymentMethod(availablePaymentMethods, "applePay");

    final session = await AdyenCheckout.session.create(
      sessionId: id,
      sessionData: sessionData,
      configuration: cardComponentConfiguration(Amount(value: 0, currency: "DKK"), clientKey),
    );

    return PaymentConfigurations(
      sessionCheckout: session,
      availablePaymentMethods: [scheme!, googlePay!, applePay!],
      googlePayConfiguration: _getGooglePayComponentConfig(clientKey),
      dropInConfiguration: dropInConfiguration(Amount(value: 0, currency: "DKK"), clientKey, true),
      cardComponentConfiguration: cardComponentConfiguration(
        Amount(value: 0, currency: "DKK"),
        clientKey,
      ),
      applePayConfiguration: _applePayComponentConfiguration(
        clientKey,
        Amount(value: 0, currency: "DKK"),
        true,
      ),
      isFullyPaidWithPoints: false,
    );
  }

  CardComponentConfiguration cardComponentConfiguration(Amount amount, String clientKey) {
    return CardComponentConfiguration(
      environment: Environment.test,
      amount: amount,
      cardConfiguration: const CardConfiguration(showStorePaymentField: false),
      clientKey: clientKey,
      countryCode: "DK",
    );
  }

  DropInConfiguration dropInConfiguration(Amount amount, String clientKey, bool addCard) {
    return DropInConfiguration(
      environment: Environment.test,
      clientKey: clientKey,
      countryCode: "DK",
      skipListWhenSinglePaymentMethod: true,
      googlePayConfiguration: _googlePayConfiguration,
      applePayConfiguration: _getApplePlayConfig(amount, addCard),
      cardConfiguration: const CardConfiguration(showStorePaymentField: false),
      paymentMethodNames: {"scheme": "Credit card"},
    );
  }

  GooglePayConfiguration get _googlePayConfiguration =>
      const GooglePayConfiguration(googlePayEnvironment: GooglePayEnvironment.test);

  GooglePayComponentConfiguration _getGooglePayComponentConfig(String clientKey) {
    return GooglePayComponentConfiguration(
      environment: Environment.test,
      countryCode: "DK",
      clientKey: clientKey,
      googlePayConfiguration: _googlePayConfiguration,
    );
  }

  ApplePayComponentConfiguration _applePayComponentConfiguration(
    String clientKey,
    Amount amount,
    bool addCard,
  ) {
    return ApplePayComponentConfiguration(
      environment: Environment.test,
      countryCode: "DK",
      clientKey: clientKey,
      applePayConfiguration: _getApplePlayConfig(amount, addCard),
    );
  }

  ApplePayConfiguration _getApplePlayConfig(Amount amount, bool addCard) {
    return ApplePayConfiguration(
      merchantId: merchantId,
      merchantName: merchantName,
      allowOnboarding: true,
      allowShippingContactEditing: true,
      applePaySummaryItems: [
        ApplePaySummaryItem(
          label: addCard ? "add_card".tr() : "total".tr(),
          amount: Amount(value: amount.value, currency: amount.currency),
          type: ApplePaySummaryItemType.definite,
        ),
      ],
    );
  }

  static final Iterable<StoredPaymentMethod> mockStoredPaymentData = [1, 2, 3, 4].map(
    (i) => StoredPaymentMethod(
      expiryMonth: "12",
      expiryYear: "2035",
      holderName: "holder name",
      id: "id $i",
      lastFour: "$i$i$i$i",
      brand: "visa",
    ),
  );
}

Map<String, dynamic>? _findPaymentMethod(Map<String, dynamic> pmResponse, String type) {
  final list =
      (pmResponse['paymentMethods'] as List?)?.cast<Map<String, dynamic>>() ??
      const <Map<String, dynamic>>[];

  for (final m in list) {
    final t = (m['type'] as String?)?.toLowerCase();
    if (t == type.toLowerCase()) {
      return m; // e.g. 'scheme', 'applepay', 'googlepay'
    }
  }
  return null;
}