/**
 *
 */
package com.braintree.method;

import com.braintree.command.request.BrainTreeAddressRequest;
import com.braintree.command.request.BrainTreeAdjustAuthorizationRequest;
import com.braintree.command.request.BrainTreeAuthorizationRequest;
import com.braintree.command.request.BrainTreeCloneTransactionRequest;
import com.braintree.command.request.BrainTreeCreateCreditCardPaymentMethodRequest;
import com.braintree.command.request.BrainTreeCreatePaymentMethodRequest;
import com.braintree.command.request.BrainTreeCustomerRequest;
import com.braintree.command.request.BrainTreeDeletePaymentMethodRequest;
import com.braintree.command.request.BrainTreeFindMerchantAccountRequest;
import com.braintree.command.request.BrainTreeFindTransactionRequest;
import com.braintree.command.request.BrainTreeGenerateClientTokenRequest;
import com.braintree.command.request.BrainTreeRefundTransactionRequest;
import com.braintree.command.request.BrainTreeSaleTransactionRequest;
import com.braintree.command.request.BrainTreeSubmitForSettlementTransactionRequest;
import com.braintree.command.request.BrainTreeTokenizeCreditCardRequest;
import com.braintree.command.request.BrainTreeUpdateCustomerRequest;
import com.braintree.command.request.BrainTreeUpdateCreditCardRequest;
import com.braintree.command.result.BrainTreeAddressResult;
import com.braintree.command.result.BrainTreeAdjustedAuthorizationResult;
import com.braintree.command.result.BrainTreeCloneTransactionResult;
import com.braintree.command.result.BrainTreeCreatePaymentMethodResult;
import com.braintree.command.result.BrainTreeCustomerResult;
import com.braintree.command.result.BrainTreeFindCustomerResult;
import com.braintree.command.result.BrainTreeFindCustomersResult;
import com.braintree.command.result.BrainTreeFindMerchantAccountResult;
import com.braintree.command.result.BrainTreeFindTransactionResult;
import com.braintree.command.result.BrainTreeGenerateClientTokenResult;
import com.braintree.command.result.BrainTreePaymentDetailsResult;
import com.braintree.command.result.BrainTreePaymentMethodNonceResult;
import com.braintree.command.result.BrainTreePaymentMethodResult;
import com.braintree.command.result.BrainTreeRefundTransactionResult;
import com.braintree.command.result.BrainTreeSaleTransactionResult;
import com.braintree.command.result.BrainTreeSubmitForSettlementTransactionResult;
import com.braintree.command.result.BrainTreeTokenizeCardResult;
import com.braintree.command.result.BrainTreeTransactionResult;
import com.braintree.command.result.BrainTreeUpdateCreditCardBillingAddressResult;
import com.braintree.command.result.BrainTreeUpdateCustomerResult;
import com.braintree.command.result.BrainTreeVoidResult;
import com.braintree.hybris.data.BrainTreeSubscriptionInfoData;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeExchangeLegacyIdRequest;
import com.braintree.hybris.data.graphql.commands.response.BraintreePaymentMethodData;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeThreeDSecure;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.braintreegateway.WebhookNotification;
import de.hybris.platform.braintree.data.BrainTreeWebhookNotificationRequest;
import de.hybris.platform.core.model.order.payment.PaymentInfoModel;
import de.hybris.platform.core.model.user.AddressModel;
import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.payment.AdapterException;
import de.hybris.platform.payment.commands.request.AuthorizationRequest;
import de.hybris.platform.payment.commands.request.CreateSubscriptionRequest;
import de.hybris.platform.payment.commands.request.VoidRequest;
import de.hybris.platform.payment.commands.result.AuthorizationResult;
import de.hybris.platform.payment.commands.result.SubscriptionResult;
import de.hybris.platform.payment.methods.PaymentMethod;

import java.util.Optional;


public interface BrainTreePaymentService extends PaymentMethod {

    SubscriptionResult createCustomerSubscription(final CreateSubscriptionRequest subscriptionRequest)
        throws AdapterException;

    BrainTreeGenerateClientTokenResult generateClientToken(final BrainTreeGenerateClientTokenRequest clientTokenRequest)
        throws AdapterException;

    BrainTreeFindCustomerResult findCustomer(final BrainTreeCustomerRequest findCustomerRequest)
        throws AdapterException;

    /**
     * Used to find customers
     * @param findCustomerRequest
     * @return BrainTreeFindCustomersResult
     * @throws AdapterException
     */
    BrainTreeFindCustomersResult findCustomers(final BrainTreeCustomerRequest findCustomerRequest)
        throws AdapterException;

    BrainTreePaymentInfoModel completeCreateSubscriptionWithCvvVerification(
            CustomerModel customer, String paymentInfoId, String cvvNonce);

    String generateClientToken(final String braintreeCustomerId);

    AuthorizationResult authorize(AuthorizationRequest authorizationRequest);

    AuthorizationResult authorize(BrainTreeAuthorizationRequest authorizationRequest, CustomerModel customer);

    /**
     * Used to get image source for payment method
     * @param cardType
     * @param paymentMethodsString
     * @return String
     */
    String getImageSourceForPaymentMethod(String cardType, final String paymentMethodsString);

    /**
     * void transaction on braintree side
     *
     * @param voidRequest
     *           request
     * @return result of void operation
     */
    BrainTreeVoidResult voidTransaction(VoidRequest voidRequest);

    /**
     * clone transaction on braintree side
     *
     * @param request
     *           simple request with transaction id, amount and submitForSettlement sign
     * @return result of clone operation
     */
    BrainTreeCloneTransactionResult cloneTransaction(BrainTreeCloneTransactionRequest request);

    /**
     * @param customer
     * @param paymentInfoId
     * @return
     */
    BrainTreePaymentInfoModel completeCreateSubscription(CustomerModel customer, String paymentInfoId);

    void saveBillingAddressIfNotExistForVenmoPaymentMethod(final BrainTreePaymentInfoModel paymentInfo);

    String generateClientToken(final String site, final String currency);

    /**
     * @param request
     * @return
     */
    BrainTreeCreatePaymentMethodResult createPaymentMethod(BrainTreeCreatePaymentMethodRequest request);

    /**
     * @param request
     * @return
     */
    BrainTreePaymentMethodResult createCreditCardPaymentMethod(BrainTreeCreateCreditCardPaymentMethodRequest request);

    /**
     * @param request
     * @return
     */
    BrainTreePaymentMethodNonceResult createPaymentMethodNonce(String request);


    /**
     * refund transaction with specific amount
     *
     * @param request
     *           wih transaction id and amount
     * @return result of refund operation
     */
    BrainTreeRefundTransactionResult refundTransaction(BrainTreeRefundTransactionRequest request);

    /**
     * update braintree customer
     *
     * @param request
     *           wih updated customer fields
     * @return result of update operation
     */
    BrainTreeUpdateCustomerResult updateCustomer(BrainTreeUpdateCustomerRequest request);

    /**
     * @param brainTreeFindMerchantAccountRequest
     *           BrainTreeFindMerchantAccountRequest
     * @return BrainTreeFindMerchantAccountResult
     */
    BrainTreeFindMerchantAccountResult findMerchantAccount(
        final BrainTreeFindMerchantAccountRequest brainTreeFindMerchantAccountRequest);

    /**
     * Used to find transactions
     * @param request
     * @return BrainTreeFindTransactionResult
     */
    BrainTreeFindTransactionResult findTransactions(final BrainTreeFindTransactionRequest request);

    /**
     * Used to find refunded transactions
     * @param request
     * @return BrainTreeFindTransactionResult
     */
    BrainTreeFindTransactionResult findRefundedTransactions(final BrainTreeFindTransactionRequest request);

    BrainTreeTransactionResult findTransactionById(String transactionId);

    /**
     * create new transaction
     *
     * @param request
     *           BrainTreeSaleTransactionRequest
     * @return BrainTreeSaleTransactionResult
     */
    BrainTreeSaleTransactionResult saleTransaction(BrainTreeSaleTransactionRequest request);

    BrainTreePaymentMethodResult deletePaymentMethod(BrainTreeDeletePaymentMethodRequest request);

    /**
     * remove customer from vault by customer id
     *
     * @param request
     *           BrainTreeCustomerRequest
     * @return BrainTreeCustomerResult
     */
    BrainTreeCustomerResult removeCustomer(BrainTreeCustomerRequest request);

    /**
     * update payment method
     *
     * @param request
     *           BrainTreeUpdatePaymentMethodRequest
     * @return BrainTreeUpdatePaymentMethodResult
     */
    BrainTreeUpdateCreditCardBillingAddressResult updatePaymentMethod(BrainTreeUpdateCreditCardRequest request);

    BrainTreeUpdateCreditCardBillingAddressResult verifyCreditCard(BrainTreeUpdateCreditCardRequest request);


    /**
     * Submit For Settlement transaction with specific amount
     *
     * @param request
     *           wih transaction id and amount
     * @return result of submit operation
     */
    BrainTreeSubmitForSettlementTransactionResult submitForSettlementTransaction(
        BrainTreeSubmitForSettlementTransactionRequest request);

    /**
     * @param addressRequest
     * @return
     */
    BrainTreeAddressResult createAddress(BrainTreeAddressRequest addressRequest, CustomerModel customer);

    /**
     *
     * @param addressRequest
     */
    BrainTreeAddressResult updateAddress(BrainTreeAddressRequest addressRequest);

    /**
     * @param addressRequest
     */
    BrainTreeAddressResult removeAddress(BrainTreeAddressRequest addressRequest);

    BrainTreeCreatePaymentMethodResult createPaymentMethodOnBraintreeOrGetExisting(final CustomerModel customer,
        final AddressModel addressModel, final BrainTreeSubscriptionInfoData subscriptionInfoData);

    BrainTreeSaleTransactionResult partialCaptureTransaction(BrainTreeSaleTransactionRequest request);

    String createCustomer(final CustomerModel customer, final AddressModel billingAddress);

    /**
     * Used to update payment info
     * @param paymentInfo
     * @param paymentDetails
     */
    void updatePaymentInfo(final PaymentInfoModel paymentInfo, final BrainTreePaymentDetailsResult paymentDetails);

    WebhookNotification getWebhookNotification(BrainTreeWebhookNotificationRequest webhookNotificationRequest);

    BrainTreePaymentDetailsResult getPaymentMethodFromBTByToken(final String paymentMethodToken);

    /**
     * Used to exchange legacy id to GraphQL id
     * @param request
     * @return String
     */
    String exchangeLegacyIdToGraphQLId(BrainTreeExchangeLegacyIdRequest request);

    /**
     * Used to tokenize credit card
     * @param request
     * @return BrainTreeTokenizeCardResult
     */
    BrainTreeTokenizeCardResult tokenizeCreditCard(BrainTreeTokenizeCreditCardRequest request);

    Optional<BrainTreePaymentDetailsResult> findPaymentMethod(BrainTreeFindCustomerResult customerResult,
        AddressModel billingAddress, BrainTreeSubscriptionInfoData subscriptionData);

    /**
     * update default payment method
     *
     * @param request
     *           customer with new default payment info
     * @return result of update operation
     */
    BrainTreeUpdateCustomerResult setBrainTreeDefaultPaymentInfo(BrainTreeUpdateCustomerRequest request);

    BrainTreeCreatePaymentMethodResult createUsBankAccountPaymentMethod(BrainTreeCreatePaymentMethodRequest request);

    BraintreePaymentMethodData getPaymentDetailsByNonce(String nonce);

    String getBraintreePing() throws AdapterException;

    BrainTreeAdjustedAuthorizationResult adjustAuthorization(final BrainTreeAdjustAuthorizationRequest request);
}
