import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:payment_plugin/utils/json.dart';

class PaymentEventHandler {
  //Response keys
  static const errorCodeKey = "errorCode";
  static const resultCodeKey = "resultCode";
  static const actionKey = "action";
  static const messageKey = "message";
  static const refusalReasonKey = "refusalReason";

  PaymentEvent handleResponse({
    required Json jsonResponse,
    Json updatedPaymentMethodsJson = const {},
  }) {
    if (_isError(jsonResponse)) {
      final message = jsonResponse[messageKey] as String?;
      final reason = jsonResponse[refusalReasonKey] as String;
      return Error(
        errorMessage: message,
        reason: message ?? reason,
        dismissDropIn: true,
      );
    }

    if (_isRefusedInPartialPaymentFlow(jsonResponse)) {
      return Error(
        errorMessage: "Payment is refused",
        reason: "Refused",
        dismissDropIn: true,
      );
    }

    if (_isAction(jsonResponse)) {
      return Action(actionResponse: jsonResponse[actionKey] as Json);
    }

    if (_isNonFullyPaidOrder(jsonResponse) &&
        updatedPaymentMethodsJson.isNotEmpty) {
      return Update(
        orderJson: jsonResponse["order"] as Json,
        paymentMethodsJson: updatedPaymentMethodsJson,
      );
    }

    if (jsonResponse.containsKey(resultCodeKey)) {
      return Finished(resultCode: jsonResponse[resultCodeKey] as String);
    }

    return Finished(resultCode: "EMPTY");
  }

  bool _isError(Json jsonResponse) {
    final hasErrorCodeKey = jsonResponse.containsKey(errorCodeKey);
    final hasErrorResultCode = (jsonResponse[resultCodeKey] as String?)
            ?.toUpperCase()
            .contains(ResultCode.error.name.toUpperCase()) ??
        false;
    return hasErrorCodeKey || hasErrorResultCode;
  }

  bool _isRefusedInPartialPaymentFlow(Json jsonResponse) =>
      _isRefused(jsonResponse) && _isNonFullyPaidOrder(jsonResponse);

  bool _isRefused(Json jsonResponse) => jsonResponse[resultCodeKey]
      .toString()
      .toUpperCase()
      .contains(ResultCode.refused.name.toUpperCase());

  bool _isAction(Json jsonResponse) => jsonResponse.containsKey(actionKey);

  bool _isNonFullyPaidOrder(Json jsonResponse) {
    if (jsonResponse.containsKey("order")) {
      final remainingAmount = jsonResponse["order"]["remainingAmount"]["value"] as num;
      return remainingAmount > 0;
    } else {
      return false;
    }
  }
}