package com.braintree.graphql.commands.impl;

import com.braintree.command.request.BrainTreeAuthorizationRequest;
import com.braintree.command.request.beans.BrainTreeLineItemBean;
import com.braintree.command.result.BrainTreeAuthorizationResult;
import com.braintree.command.result.BrainTreePaymentDetailsResult;
import com.braintree.commands.impl.AbstractAuthorizationCommand;
import com.braintree.customer.service.BrainTreeCustomerAccountService;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeAddressInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeChargeCreditCardInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeChargePaymentMethodInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeChargeVenmoAccountInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeChargeVenmoAccountOptionsInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeCreditCardFraudToolsOptionsInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeCreditCardTransactionOptionsInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeRiskDataInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeTransactionInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeTransactionLineItemInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeTransactionShippingInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeTransactionTaxInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeVaultPaymentMethodAfterTransactingInput;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeVaultPaymentMethodCriteria;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeErrorDefinition;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodSnapshot;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentStatus;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeRiskData;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransactionPayload;
import com.braintree.hybris.data.graphql.commands.response.BraintreePaymentMethodData;
import com.braintree.method.BrainTreePaymentService;
import com.braintree.payment.info.service.BraintreePaymentInfoService;
import com.braintree.service.BrainTreeDescriptorService;
import com.braintree.util.BrainTreeUtils;
import com.braintreegateway.TransactionLineItem;
import de.hybris.platform.payment.AdapterException;
import de.hybris.platform.payment.commands.AuthorizationCommand;
import de.hybris.platform.payment.commands.request.AuthorizationRequest;
import de.hybris.platform.payment.commands.result.AuthorizationResult;
import de.hybris.platform.payment.dto.AvsStatus;
import de.hybris.platform.payment.dto.BillingInfo;
import de.hybris.platform.payment.dto.CvnStatus;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.payment.dto.TransactionStatusDetails;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import de.hybris.platform.servicelayer.util.ServicesUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.util.Strings;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.braintree.constants.BraintreeConstants.INPUT_PARAMETER;
import static com.braintree.constants.BraintreeConstants.RESULT_DATA;
import static com.braintree.constants.BraintreeConstants.RESULT_ERRORS;

public class DefaultBrainTreeGraphQLAuthorizationCommand extends AbstractAuthorizationCommand
        implements AuthorizationCommand {

    private static final Logger LOG = Logger.getLogger(DefaultBrainTreeGraphQLAuthorizationCommand.class);

    private static final String DEFINITION_FILE_NAME_CHARGE_PAYPAL = "chargePayPalAccount";
    private static final String DEFINITION_FILE_NAME_CHARGE_VENMO = "chargeVenmoAccount";
    private static final String DEFINITION_FILE_NAME_CHARGE_CREDIT_CARD = "chargeCreditCard";
    private static final String DEFINITION_FILE_NAME_CHARGE = "chargePaymentMethod";
    private static final String DEFINITION_FILE_NAME_AUTHORIZATION_PAYPAL = "authorizePayPalAccount";
    private static final String DEFINITION_FILE_NAME_AUTHORIZATION_VENMO = "authorizeVenmoAccount";
    private static final String DEFINITION_FILE_NAME_AUTHORIZATION_CREDIT_CARD = "authorizeCreditCard";
    private static final String DEFINITION_FILE_NAME_AUTHORIZATION = "authorizePaymentMethod";

    private BrainTreePaymentService brainTreePaymentService;
    private BrainTreeDescriptorService brainTreeDescriptorService;
    private BrainTreeCustomerAccountService brainTreeCustomerAccountService;
    private BraintreePaymentInfoService paymentInfoService;
    private Converter<BillingInfo, BrainTreeAddressInput> braintreeBillingInfoToGraphQLAddressInputConverter;
    private Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> graphQLPaymentMethodToPaymentDetailsConverter;

    private Map<String, Function<BrainTreeAuthorizationRequest, BrainTreeChargePaymentMethodInput>> createInputByMutation;

    protected void initMethod() {
        createInputByMutation = new HashMap<>();

        createInputByMutation.put(DEFINITION_FILE_NAME_CHARGE_PAYPAL,
                this::createDefaultInput);
        createInputByMutation.put(DEFINITION_FILE_NAME_CHARGE_VENMO,
                this::createInputForVenmo);
        createInputByMutation.put(DEFINITION_FILE_NAME_CHARGE_CREDIT_CARD,
                this::createInputForCreditCard);
        createInputByMutation.put(DEFINITION_FILE_NAME_CHARGE,
                this::createDefaultInput);
        createInputByMutation.put(DEFINITION_FILE_NAME_AUTHORIZATION_PAYPAL,
                this::createDefaultInput);
        createInputByMutation.put(DEFINITION_FILE_NAME_AUTHORIZATION_VENMO,
                this::createInputForVenmo);
        createInputByMutation.put(DEFINITION_FILE_NAME_AUTHORIZATION_CREDIT_CARD,
                this::createInputForCreditCard);
        createInputByMutation.put(DEFINITION_FILE_NAME_AUTHORIZATION,
                this::createDefaultInput);
    }

    @Override
    public AuthorizationResult perform(AuthorizationRequest authorizationRequest) {
        LOG.info("Configured intent: " + getBrainTreeConfigService().getIntent());
        try {
            String fileDefinition = getMutationFileDefinition(authorizationRequest);
            Map<String, Object> result = makeGraphQlCall(fileDefinition,
                    createVariablesMap(fileDefinition, authorizationRequest));
            ArrayList<Map<String, Object>> mapErrors = (ArrayList<Map<String, Object>>) result.get(RESULT_ERRORS);

            LOG.info("BraintreeReply: " + result);

            final BrainTreeAuthorizationResult authorizationResult = translateResponse(
                    (Map<String, Object>) result.get(RESULT_DATA), mapErrors, fileDefinition);

            authorizationResult.setRequestBody(parseToJson(createVariablesMap(fileDefinition, authorizationRequest)));
            authorizationResult.setResponseBody(parseToJson(result));

            if (authorizationResult.isSuccess()) {
                authorizationResult.setShouldGetMethodTokenFromBraintree(
                        shouldGetPaymentMethodTokenFromBraintree(authorizationResult, authorizationRequest));
            }

            return authorizationResult;
        } catch (IOException e) {
            LOG.error("Can't load mutation from file. " + e);
            throw new AdapterException("Error during authorization");
        }
    }

    private BrainTreeAuthorizationResult translateResponse(Map<String, Object> data,
                                                           ArrayList<Map<String, Object>> errors, String mutationName) {
        final BrainTreeAuthorizationResult authorizationResult = new BrainTreeAuthorizationResult();
        authorizationResult.setTransactionStatus(TransactionStatus.REJECTED);
        if (data == null) {
            return authorizationResult;
        }

        BrainTreeTransactionPayload payload = objectMapper
                .convertValue(data.get(mutationName), BrainTreeTransactionPayload.class);

        if (errors == null && payload.getTransaction() != null && payload.getTransaction().getStatus().isSuccess()) {
            authorizationResult.setSuccess(true);
            processSuccessReply(authorizationResult, payload);
        } else if (errors != null) {
            authorizationResult.setSuccess(false);
            List<BrainTreeErrorDefinition> errorDefinitions = errors.stream()
                    .map(stringObjectMap -> objectMapper.convertValue(stringObjectMap, BrainTreeErrorDefinition.class))
                    .collect(Collectors.toList());
            processErrorReply(errorDefinitions, payload, authorizationResult);
        } else {
            authorizationResult.setSuccess(false);
            processErrorReply(null, payload, authorizationResult);
        }

        String btFraudCheckToolDecision = Optional.ofNullable(payload)
                .map(BrainTreeTransactionPayload::getTransaction)
                .map(BrainTreeTransaction::getRiskData)
                .map(BrainTreeRiskData::getDecision)
                .orElse(Strings.EMPTY);
        authorizationResult.setBtFraudCheckToolDecision(btFraudCheckToolDecision);

        getLoggingHandler().handleResult(AUTHORIZATION_TRANSACTION, payload);

        return authorizationResult;
    }

    private void processSuccessReply(final BrainTreeAuthorizationResult result,
                                     final BrainTreeTransactionPayload payload) {
        if (payload != null && payload.getTransaction() != null) {
            BrainTreeTransaction transaction = payload.getTransaction();

            result.setAvsStatus(AvsStatus.MATCHED);
            result.setCvnStatus(CvnStatus.MATCHED);

            if (transaction.getAmount() != null) {
                result.setTotalAmount(new BigDecimal(transaction.getAmount().getValue()));
            }

            result.setStatus(transaction.getStatus().name());
            result.setAuthorizationTime(transaction.getCreatedAt().getTime());
            result.setCurrency(Currency.getInstance(transaction.getAmount().getCurrencyCode()));
            result.setMerchantTransactionCode(transaction.getMerchantAccountId());
            result.setRequestId(transaction.getLegacyId());
            result.setRequestGraphQLId(transaction.getId());
            result.setRequestToken(transaction.getLegacyId());
            result.setTransactionStatus(TransactionStatus.ACCEPTED);
            result.setTransactionStatusDetails(TransactionStatusDetails.SUCCESFULL);

            BrainTreePaymentDetailsResult paymentDetails = parsePaymentDetailsResult(payload);
            BrainTreePaymentMethodSnapshot paymentMethodSnapshot = transaction.getPaymentMethodSnapshot();
            result.setCaptureId(paymentMethodSnapshot.getCaptureId());
            paymentDetails.setPaymentInstrumentType(
                    paymentInfoService.getPaymentInstrumentTypeBySnapshotAndOrigin(paymentMethodSnapshot));

            result.setPaymentDetails(paymentDetails);
            result.setMessage(getMessageByStatus(transaction.getStatusHistory(), transaction.getStatus()));
            result.setStatusCode(getCodeByStatus(transaction.getStatusHistory()));
        } else {
            result.setSuccess(false);
            result.setTransactionStatusDetails(TransactionStatusDetails.BANK_DECLINE);
        }
    }

    private BrainTreePaymentDetailsResult parsePaymentDetailsResult(final BrainTreeTransactionPayload payload) {
        BrainTreePaymentDetailsResult paymentDetailsResult = new BrainTreePaymentDetailsResult();

        BraintreePaymentMethodData paymentMethod = payload.getTransaction().getPaymentMethod();
        if (paymentMethod == null && payload.getBillingAgreementWithPurchasePaymentMethod() != null) {
            paymentMethod = payload.getBillingAgreementWithPurchasePaymentMethod();
        }

        if (paymentMethod != null) {
            paymentDetailsResult = graphQLPaymentMethodToPaymentDetailsConverter.convert(paymentMethod);
        }

        return paymentDetailsResult;
    }

    private void processErrorReply(List<BrainTreeErrorDefinition> errors, BrainTreeTransactionPayload payload,
                                   final BrainTreeAuthorizationResult result) {
        if (payload == null || payload.getTransaction() == null) {
            result.setRequestId("N/A");
            result.setAuthorizationTime(new Date()); // in this case timestamp not available in the response
        } else {
            result.setRequestId(payload.getTransaction().getLegacyId());
            result.setRequestGraphQLId(payload.getTransaction().getId());
            result.setAuthorizationTime(payload.getTransaction().getCreatedAt().getTime());
            result.setTotalAmount(new BigDecimal(payload.getTransaction().getAmount().getValue()));
            result.setCurrency(Currency.getInstance(payload.getTransaction().getAmount().getCurrencyCode()));
            result.setMerchantTransactionCode(payload.getTransaction().getMerchantAccountId());
            BrainTreePaymentDetailsResult paymentDetails = parsePaymentDetailsResult(payload);
            BrainTreePaymentMethodSnapshot paymentMethodSnapshot = payload.getTransaction().getPaymentMethodSnapshot();
            paymentDetails.setPaymentInstrumentType(
                    paymentInfoService.getPaymentInstrumentTypeBySnapshotAndOrigin(paymentMethodSnapshot));

            result.setPaymentDetails(paymentDetails);
        }

        if (errors != null && errors.size() > 0) {
            getLoggingHandler().handleErrors(errors);
            result.setStatus(BrainTreePaymentStatus.FAILED.name());
            result.setTransactionStatusDetails(getCodeTranslator()
                    .translateReasonCode(errors.get(0).getExtensions().getLegacyCode()));
            result.setMessage(errors.get(0).getMessage());
            result.setStatusCode(errors.get(0).getExtensions().getLegacyCode());
        } else if (payload != null && payload.getTransaction() != null) {
            result.setStatus(payload.getTransaction().getStatus().name());
            result.setTransactionStatusDetails(TransactionStatusDetails.PROCESSOR_DECLINE);
            result.setMessage(getMessageByStatus(payload.getTransaction().getStatusHistory(), payload.getTransaction().getStatus()));
            result.setStatusCode(getCodeByStatus(payload.getTransaction().getStatusHistory()));
        }
        LOG.error(String.format("[ERROR AUTHORIZATION] Code: %s, Status: %s", result.getStatusCode(), result.getMessage()));
    }

    private String getMutationFileDefinition(AuthorizationRequest authorizationRequest) {
        String result = DEFINITION_FILE_NAME_CHARGE;

        if (authorizationRequest instanceof BrainTreeAuthorizationRequest) {
            final BrainTreeAuthorizationRequest request = (BrainTreeAuthorizationRequest) authorizationRequest;

            boolean submitForSettlement = request.getSubmitForSettlement();

            if (BrainTreeUtils.isVenmoPayment(request.getPaymentType())) {
                result = submitForSettlement ? DEFINITION_FILE_NAME_CHARGE_VENMO
                        : DEFINITION_FILE_NAME_AUTHORIZATION_VENMO;
            } else if (BrainTreeUtils.isPayPalPayment(request.getPaymentType())) {
                result = submitForSettlement ? DEFINITION_FILE_NAME_CHARGE_PAYPAL
                        : DEFINITION_FILE_NAME_AUTHORIZATION_PAYPAL;
            } else if (isCreditCardOfAnyOrigin(request.getPaymentType())) {
                result = submitForSettlement ? DEFINITION_FILE_NAME_CHARGE_CREDIT_CARD
                        : DEFINITION_FILE_NAME_AUTHORIZATION_CREDIT_CARD;
            } else {
                result = submitForSettlement ? DEFINITION_FILE_NAME_CHARGE
                        : DEFINITION_FILE_NAME_AUTHORIZATION;
            }
        }
        return result;
    }

    private BrainTreeChargePaymentMethodInput createInputForVenmo(BrainTreeAuthorizationRequest request) {
        final BrainTreeChargeVenmoAccountInput venmoAccountInput = new BrainTreeChargeVenmoAccountInput();
        if (StringUtils.isNotBlank(request.getVenmoProfileId())) {
            BrainTreeChargeVenmoAccountOptionsInput optionsInput = new BrainTreeChargeVenmoAccountOptionsInput();
            optionsInput.setProfileId(request.getVenmoProfileId());
            venmoAccountInput.setOptions(optionsInput);
        }
        return venmoAccountInput;
    }

    private BrainTreeChargePaymentMethodInput createInputForCreditCard(BrainTreeAuthorizationRequest request) {
        final BrainTreeChargeCreditCardInput creditCardInput = new BrainTreeChargeCreditCardInput();
        final BillingInfo billingInfo = request.getBillingInfo();
        final BrainTreeCreditCardTransactionOptionsInput options = new BrainTreeCreditCardTransactionOptionsInput();
        if (billingInfo != null) {
            final BrainTreeAddressInput addressInput = braintreeBillingInfoToGraphQLAddressInputConverter
                    .convert(billingInfo);
            options.setBillingAddress(addressInput);
        }
        final BrainTreeCreditCardFraudToolsOptionsInput fraudToolsOptionsInput =
                new BrainTreeCreditCardFraudToolsOptionsInput();
        fraudToolsOptionsInput.setSkipAdvancedFraudChecking(!request.getAdvancedFraudTools());
        options.setFraudTools(fraudToolsOptionsInput);

        creditCardInput.setOptions(options);
        return creditCardInput;
    }

    private BrainTreeChargePaymentMethodInput createDefaultInput(BrainTreeAuthorizationRequest request) {
        return new BrainTreeChargePaymentMethodInput();
    }

    private Map<String, Object> createVariablesMap(final String mutation,
                                                   final AuthorizationRequest authorizationRequest) {
        Map<String, Object> map = new HashMap<>();

        if (authorizationRequest instanceof BrainTreeAuthorizationRequest) {
            final BrainTreeAuthorizationRequest request = (BrainTreeAuthorizationRequest) authorizationRequest;

            BrainTreeChargePaymentMethodInput input = createInputByMutation.get(mutation).apply(request);
            BrainTreeTransactionInput transaction = new BrainTreeTransactionInput();
            input.setTransaction(transaction);

            if (StringUtils.isNotEmpty(request.getCustomerId())) {
                transaction
                        .setCustomerId(brainTreeCustomerAccountService.getGraphQLIdForCustomer(request.getCustomerId()));
            }
            transaction.setAmount(authorizationRequest.getTotalAmount());

            setAdditionalParameters(input, request);

            boolean level2Level3Enabled = getBrainTreeConfigService().getBrainTreePluginConfiguration()
                    .getBraintreeGeneralConfiguration().isLevel2Level3();

            LOG.info("if Level2 enabled: " + level2Level3Enabled);
            //                validate Level2 fields, if valid then apply to request
            if (level2Level3Enabled && isLevel2Applicable(request)) {
                BrainTreeTransactionTaxInput tax = new BrainTreeTransactionTaxInput();
                tax.setTaxAmount(roundNumberToTwoDecimalPlaces(request.getTaxAmountAuthorize()));
                input.getTransaction().setTax(tax);

                //                    validate Level3 fields, if valid then apply to request
                if (!BrainTreeUtils.isPayPalPayment(request.getPaymentType())) {
                    LOG.info("Apply Level3 data, order: " + request.getPurchaseOrderNumber());

                    input.getTransaction().getShipping()
                            .setShippingAmount(roundNumberToTwoDecimalPlaces(request.getShippingAmount()).toString());

                    input.getTransaction()
                            .setDiscountAmount(roundNumberToTwoDecimalPlaces(request.getDiscountAmount()).toString());

                    input.getTransaction().getShipping().setShipsFromPostalCode(request.getShipsFromPostalCode());

                    input.getTransaction().getShipping().getShippingAddress()
                            .setPostalCode(request.getShippingPostalCode());

                    List<BrainTreeTransactionLineItemInput> lineItems = createListTransactionLineItemInput(request);

                    input.getTransaction().setLineItems(lineItems);
                }

            }

            getLoggingHandler().handleAuthorizationRequest(request);
            map.put(INPUT_PARAMETER, input);

        } else {
            final String errorMessage = "[BT Authorization Error] Authorization Request must be Brain Tree type!";
            getLoggingHandler().getLogger().error(errorMessage);
            throw new AdapterException(errorMessage);
        }
        return map;
    }

    private List<BrainTreeTransactionLineItemInput> createListTransactionLineItemInput(
            BrainTreeAuthorizationRequest request) {
        List<BrainTreeTransactionLineItemInput> lineItems = new ArrayList<>();
        for (final BrainTreeLineItemBean bean : request.getLineItems()) {
            BrainTreeTransactionLineItemInput lineItem = new BrainTreeTransactionLineItemInput();

            lineItem.setName(bean.getName());
            lineItem.setKind(TransactionLineItem.Kind.DEBIT.name());
            lineItem.setQuantity(bean.getQuantity().toString());
            lineItem.setUnitAmount(bean.getUnitAmount().toString());
            lineItem.setUnitOfMeasure(bean.getUnitOfMeasure());
            lineItem.setTotalAmount(bean.getTotalAmount().toString());
            lineItem.setTaxAmount(bean.getTaxAmount().toString());
            lineItem.setDiscountAmount(bean.getDiscountAmount().toString());
            lineItem.setProductCode(bean.getProductCode());
            lineItem.setCommodityCode(bean.getCommodityCode());

            lineItems.add(lineItem);
        }
        return lineItems;
    }

    private void setAdditionalParameters(BrainTreeChargePaymentMethodInput input,
                                         BrainTreeAuthorizationRequest brainTreeAuthorizationRequest) {

        final boolean isAlreadyVaulted = brainTreeAuthorizationRequest.getUsePaymentMethodToken();

        if (isAlreadyVaulted && !brainTreeAuthorizationRequest.isThreeDSecureFlow()) {
            ServicesUtil.validateParameterNotNull(brainTreeAuthorizationRequest.getPaymentMethodToken(),
                    "Error: PaymentMethodToken is null!");
            String token = brainTreeAuthorizationRequest.getPaymentMethodGraphQLToken();
            if (token == null) {
                token = paymentInfoService
                        .getGraphQLTokenForPaymentMethod(brainTreeAuthorizationRequest.getPaymentMethodToken());
            }
            input.setPaymentMethodId(token);
            input.getTransaction().setCustomerId(null);
        } else {
            input.setPaymentMethodId(brainTreeAuthorizationRequest.getMethodNonce());
        }

        final boolean storeInVaultForCard = getBrainTreeConfigService()
                .isStoreInVaultForCardVaulting(brainTreeAuthorizationRequest.getCustomerId());
        if (!isAlreadyVaulted && storeInVaultForCard) {
            BrainTreeVaultPaymentMethodAfterTransactingInput vault = new BrainTreeVaultPaymentMethodAfterTransactingInput();
            vault.setWhen(BrainTreeVaultPaymentMethodCriteria.ON_SUCCESSFUL_TRANSACTION);
            input.getTransaction().setVaultPaymentMethodAfterTransacting(vault);
        }

        if (Boolean.TRUE.equals(brainTreeAuthorizationRequest.getAdvancedFraudTools())) {
            BrainTreeRiskDataInput riskData = new BrainTreeRiskDataInput();
            riskData.setDeviceData(brainTreeAuthorizationRequest.getDeviceData());
            input.getTransaction().setRiskData(riskData);
        }

        input.getTransaction().setPaymentInitiator(brainTreeAuthorizationRequest.getPaymentInitiator());

        final BillingInfo shippingInfo = brainTreeAuthorizationRequest.getShippingInfo();

        BrainTreeTransactionShippingInput shippingInput = new BrainTreeTransactionShippingInput();
        BrainTreeAddressInput addressInput = braintreeBillingInfoToGraphQLAddressInputConverter.convert(shippingInfo);
        shippingInput.setShippingAddress(addressInput);
        input.getTransaction().setShipping(shippingInput);

        input.getTransaction().setChannel(getBrainTreeConfigService().getBrainTreeChannel());
        brainTreeAuthorizationRequest.setBrainTreeChannel(getBrainTreeConfigService().getBrainTreeChannel());
        input.getTransaction()
                .setMerchantAccountId(brainTreeAuthorizationRequest.getMerchantAccountIdForCurrentSite());
        input.getTransaction().setOrderId(brainTreeAuthorizationRequest.getBrainTreeOrderId());

        String paymentType = brainTreeAuthorizationRequest.getPaymentType();
        if (brainTreeDescriptorService.isDescriptorAvailable(paymentType)) {
            input.getTransaction().setDescriptor(brainTreeDescriptorService.getTransactionDescriptor(paymentType));
        }

        setCustomFields(input.getTransaction(), brainTreeAuthorizationRequest.getCustomFields());
    }

    private boolean isCreditCardOfAnyOrigin(String paymentType) {
        return BrainTreeUtils.isCreditCardPayment(paymentType)
                || BrainTreeUtils.isGooglePayment(paymentType)
                || BrainTreeUtils.isApplePayPayment(paymentType)
                || BrainTreeUtils.isSrcPayment(paymentType);
    }

    public BrainTreePaymentService getBrainTreePaymentService() {
        return brainTreePaymentService;
    }

    public void setBrainTreePaymentService(BrainTreePaymentService brainTreePaymentService) {
        this.brainTreePaymentService = brainTreePaymentService;
    }

    public BrainTreeCustomerAccountService getBrainTreeCustomerAccountService() {
        return brainTreeCustomerAccountService;
    }

    public void setBrainTreeCustomerAccountService(
            BrainTreeCustomerAccountService brainTreeCustomerAccountService) {
        this.brainTreeCustomerAccountService = brainTreeCustomerAccountService;
    }

    public BraintreePaymentInfoService getPaymentInfoService() {
        return paymentInfoService;
    }

    public void setPaymentInfoService(BraintreePaymentInfoService paymentInfoService) {
        this.paymentInfoService = paymentInfoService;
    }

    public Converter<BillingInfo, BrainTreeAddressInput> getBraintreeBillingInfoToGraphQLAddressInputConverter() {
        return braintreeBillingInfoToGraphQLAddressInputConverter;
    }

    public void setBraintreeBillingInfoToGraphQLAddressInputConverter(
            Converter<BillingInfo, BrainTreeAddressInput> braintreeBillingInfoToGraphQLAddressInputConverter) {
        this.braintreeBillingInfoToGraphQLAddressInputConverter = braintreeBillingInfoToGraphQLAddressInputConverter;
    }

    public Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> getGraphQLPaymentMethodToPaymentDetailsConverter() {
        return graphQLPaymentMethodToPaymentDetailsConverter;
    }

    public void setGraphQLPaymentMethodToPaymentDetailsConverter(
            Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> graphQLPaymentMethodToPaymentDetailsConverter) {
        this.graphQLPaymentMethodToPaymentDetailsConverter = graphQLPaymentMethodToPaymentDetailsConverter;
    }

    public void setBrainTreeDescriptorService(BrainTreeDescriptorService brainTreeDescriptorService) {
        this.brainTreeDescriptorService = brainTreeDescriptorService;
    }
}
