package com.braintree.configuration.service;

import com.braintree.daos.BrainTreeBaseStoreDao;
import com.braintree.enums.BraintreeIntent;
import com.braintree.enums.BraintreePageType;
import com.braintree.enums.BraintreeThreeDSecureFlow;
import com.braintree.exceptions.BrainTreePluginConfigurationNotFound;
import com.braintreegateway.Environment;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.core.model.BraintreePluginConfigurationModel;
import de.hybris.platform.core.model.BraintreeGeneralConfigurationModel;
import de.hybris.platform.core.model.BraintreeHostedFieldsConfigurationModel;
import de.hybris.platform.core.model.BraintreePayPalConfigurationModel;
import de.hybris.platform.core.model.BraintreeVenmoConfigurationModel;
import de.hybris.platform.core.model.BraintreeGooglePayConfigurationModel;
import de.hybris.platform.core.model.BraintreeSRCConfigurationModel;
import de.hybris.platform.core.model.BraintreeApplePayConfigurationModel;
import de.hybris.platform.core.model.BraintreeLocalPaymentsConfigurationModel;
import de.hybris.platform.core.model.BraintreeACHConfigurationModel;
import de.hybris.platform.core.model.BraintreeConnectWithPayPalConfigurationModel;
import de.hybris.platform.core.model.c2l.CurrencyModel;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import de.hybris.platform.servicelayer.i18n.CommonI18NService;
import de.hybris.platform.servicelayer.user.UserService;
import de.hybris.platform.site.BaseSiteService;
import de.hybris.platform.store.BaseStoreModel;
import de.hybris.platform.store.services.BaseStoreService;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Arrays;
import java.util.Optional;

import static com.braintree.constants.BraintreeConstants.BRAINTREE_DISABLE_FUNDING_ON_MY_ACCOUNT;
import static com.braintree.constants.BraintreeConstants.CARD_FUNDING_SOURCE;
import static com.braintree.constants.BraintreeConstants.ENVIRONMENT_SANDBOX;
import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_SCRIPT;
import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_SCOPES;
import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_RESPONSE_TYPE;
import static com.braintree.constants.BraintreeConstants.CLIENT_ID;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_DISPLAY_NAME;
import static com.braintree.constants.BraintreeConstants.SECRET_KEY;
import static com.braintree.constants.BraintreeConstants.PAYPAL_API_URL;
import static com.braintree.constants.BraintreeConstants.COMMA_SEPARATOR;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.HYBRIS_BUILD_API_VERSION;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.MULTICAPTURE_ENABLED;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ACCEPTED_CREDIT_CARD_PAYMENT_METHODS;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ACCEPTED_PAYMENT_METHODS;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_IMAGES_PREFIX;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SEARCH_LIMIT;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_LOCALE;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.B2C_ENDPOINT_URL_PROPERTY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ENVIRONMENT;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_USER_ACTION;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SRC_SDK_URL;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SRC_IMG_URL;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_KEY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_CHANNEL_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.mock;


@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeConfigServiceTest {

    private static final String CREDIT = "CREDIT";
    private static final String MERCHANT_NAME = "MERCHANT_NAME";
    private static final String BILLING_AGREEMENT_TEXT = "BILLING_AGREEMENT_TEXT";
    private static final String PAYMENT_METHOD1 = "PAYMENT_METHOD1";
    private static final String IMAGE_LINK1 = "IMAGE_LINK1";
    private static final String PAYMENT_METHOD2 = "PAYMENT_METHOD2";
    private static final String IMAGE_LINK2 = "IMAGE_LINK2";
    private static final String PAYMENT_METHODS_STRING_ONE_PAYMENT = PAYMENT_METHOD1;
    private static final String PAYMENT_METHODS_STRING_MORE_THAN_ONE_PAYMENT = PAYMENT_METHOD1 + ";" + PAYMENT_METHOD2;
    public static final String ENVIRONMENT_DEVELOPMENT = "development";
    private static final String MERCHANT_ACCOUNT_ID = "MERCHANT_ACCOUNT_ID";
    private static final String BRAINTREE_CUSTOMER_ID = "braintreeId";
    private static final String UID = "uid";
    private static final String US = "US";
    private static final String ISO_CODE = "ISO_CODE";
    private static final String URL = "URL";
    private static final String KEY = "KEY";
    private static final String USER_ACTION = "USER_ACTION";
    public static final String HYBRIS_BT = "Hybris_BT";
    private static final String CONNECT_SCRIPT = "CONNECT_SCRIPT";
    private static final String CONNECT_SCOPES = "CONNECT_SCOPES";
    private static final String CONNECT_RESPONSE_TYPE = "CONNECT_RESPONSE_TYPE";
    private static final String DISABLE_FUNDING = CREDIT.toLowerCase() + COMMA_SEPARATOR + BRAINTREE_DISABLE_FUNDING_ON_MY_ACCOUNT;
    private static final int ONE = 1;

    @Mock
    private BraintreePluginConfigurationModel pluginConfigurationModel;
    @Mock
    private BraintreeGeneralConfigurationModel generalConfigurationModel;
    @Mock
    private BraintreeHostedFieldsConfigurationModel hostedFieldsConfigurationModel;
    @Mock
    private BraintreePayPalConfigurationModel payPalConfigurationModel;
    @Mock
    private BraintreeVenmoConfigurationModel venmoConfigurationModel;
    @Mock
    private BraintreeGooglePayConfigurationModel googlePayConfigurationModel;
    @Mock
    private BraintreeSRCConfigurationModel srcConfigurationModel;
    @Mock
    private BraintreeApplePayConfigurationModel applePayConfigurationModel;
    @Mock
    private BraintreeLocalPaymentsConfigurationModel localPaymentsConfigurationModel;
    @Mock
    private BraintreeACHConfigurationModel achConfigurationModel;
    @Mock
    private BraintreeConnectWithPayPalConfigurationModel connectWithPayPalConfigurationModel;
    @Mock
    private Configuration configuration;
    @Mock
    private Map<String, String> merchantAccountIds;

    @Mock
    private ConfigurationService configurationService;
    @Mock
    private BaseSiteService baseSiteService;
    @Mock
    private BaseStoreService baseStoreService;
    @Mock
    private CommonI18NService commonI18NService;
    @Mock
    private UserService userService;
    @Mock
    private BrainTreeBaseStoreDao brainTreeBaseStoreDao;

    @Spy
    @InjectMocks
    private BrainTreeConfigService unit;

    @Before
    public void init() {
        merchantAccountIds = new HashMap<>();
        merchantAccountIds.put(ISO_CODE, MERCHANT_ACCOUNT_ID);

        when(pluginConfigurationModel.getBraintreeGeneralConfiguration()).thenReturn(generalConfigurationModel);
        when(generalConfigurationModel.getMerchantAccountId()).thenReturn(merchantAccountIds);

        when(pluginConfigurationModel.getBraintreeHostedFieldsConfiguration()).thenReturn(hostedFieldsConfigurationModel);
        when(pluginConfigurationModel.getBraintreePayPalConfiguration()).thenReturn(payPalConfigurationModel);
        when(pluginConfigurationModel.getBraintreeVenmoConfiguration()).thenReturn(venmoConfigurationModel);
        when(pluginConfigurationModel.getBraintreeGooglePayConfiguration()).thenReturn(googlePayConfigurationModel);
        when(pluginConfigurationModel.getBraintreeSRCConfiguration()).thenReturn(srcConfigurationModel);
        when(pluginConfigurationModel.getBraintreeApplePayConfiguration()).thenReturn(applePayConfigurationModel);
        when(pluginConfigurationModel.getBraintreeLocalPaymentsConfiguration()).thenReturn(localPaymentsConfigurationModel);
        when(pluginConfigurationModel.getBraintreeACHConfiguration()).thenReturn(achConfigurationModel);
        when(pluginConfigurationModel.getBraintreeConnectWithPayPalConfiguration()).thenReturn(connectWithPayPalConfigurationModel);
        when(configurationService.getConfiguration()).thenReturn(configuration);
    }

    @Test
    public void shouldGetThreeDSecureFlow() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getBraintreeThreeDSecureFlow()).thenReturn(BraintreeThreeDSecureFlow.ALWAYS);
        assertEquals(BraintreeThreeDSecureFlow.ALWAYS, unit.getThreeDSecureFlow());
    }

    @Test
    public void shouldGetAdvancedFraudTools() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isAdvancedFraudTools()).thenReturn(true);
        assertTrue(unit.isAdvancedFraudTools());
    }

    @Test
    public void shouldGetApplePayEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(applePayConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isApplePayEnabled());
    }

    @Test
    public void shouldGetApplePayOnExpressCheckoutEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(applePayConfigurationModel.isExpressCheckout()).thenReturn(true);
        assertTrue(unit.isApplePayOnExpressCheckoutEnabled());
    }

    @Test
    public void shouldGetChangePaymentButtonEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isChangePaymentMethodButton()).thenReturn(true);
        assertTrue(unit.isChangePaymentMethodButtonEnabled());
    }

    @Test
    public void shouldGetPayPalDisableFunding() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.getDisableFunding()).thenReturn(CREDIT);
        assertEquals(CREDIT, unit.getPayPalDisableFunding());
    }

    @Test
    public void shouldGetPayLaterEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isPayLater()).thenReturn(true);
        assertTrue(unit.isPayLaterEnabled());
    }

    @Test
    public void shouldGetDropInEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isDropIn()).thenReturn(true);
        assertTrue(unit.isDropInEnabled());
    }

    @Test
    public void shouldGetGooglePayEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(googlePayConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isGooglePayEnabled());
    }

    @Test
    public void shouldGetGooglePayOnExpressCheckoutEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(googlePayConfigurationModel.isExpressCheckout()).thenReturn(true);
        assertTrue(unit.isGooglePayOnExpressCheckoutEnabled());
    }

    @Test
    public void shouldHostedFieldEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isHostedFieldEnabled());
    }

    @Test
    public void shouldLocalPaymentsEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(localPaymentsConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isLocalPaymentsEnabled());
    }

    @Test
    public void shouldMultiCaptureEnabled() {
        when(configuration.getBoolean(MULTICAPTURE_ENABLED, true)).thenReturn(true);
        assertTrue(unit.isMultiCaptureEnabled());
    }

    @Test
    public void isPayPalEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isPayPalEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isHostedFieldEnabledEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isVenmoEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(venmoConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isLocalPaymentsEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(localPaymentsConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isApplePayEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(applePayConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isGooglePayEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(googlePayConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void isSRCEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(srcConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void ifNoOneOfPaymentMethodsEnabledShouldReturnFalse() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        assertFalse(unit.isOneOfPaymentMethodsEnabled());
    }

    @Test
    public void shouldPayLaterEnabledForNonUsCountries() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isPayLaterForNonUsCountries()).thenReturn(true);
        assertTrue(unit.isPayLaterEnabledForNonUsCountries());
    }

    @Test
    public void shouldPayPalExpressEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isExpressCheckout()).thenReturn(true);
        assertTrue(unit.isPayPalExpressEnabled());
    }

    @Test
    public void shouldGetPayPalEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.isPayPalEnabled()).thenReturn(true);
        assertTrue(unit.isPayPalEnabled());
    }

    @Test
    public void shouldGetTrue3dSecureConfiguration() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getBraintreeThreeDSecureFlow()).thenReturn(BraintreeThreeDSecureFlow.AUTO);
        assertTrue(unit.is3dSecureConfiguration());
    }

    @Test
    public void shouldGetFalse3dSecureConfiguration() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getBraintreeThreeDSecureFlow()).thenReturn(BraintreeThreeDSecureFlow.DISABLED);
        assertFalse(unit.is3dSecureConfiguration());
    }

    @Test
    public void shouldGetSrcEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(srcConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isSrcEnabled());
    }

    @Test
    public void shouldGetStoreInVault() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isStoreInVault()).thenReturn(true);
        assertTrue(unit.isStoreInVault());
    }

    @Test
    public void getStoreInVaultForCurrentUserShouldReturnFalseIfCustomerAnonymous() {
        when(userService.isAnonymousUser(any())).thenReturn(true);
        assertFalse(unit.isStoreInVaultForCurrentUser());
    }

    @Test
    public void getStoreInVaultForCurrentUserShouldReturnTrue() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isStoreInVault()).thenReturn(true);
        assertTrue(unit.isStoreInVaultForCurrentUser());
    }

    @Test
    public void getStoreInVaultForCardVaultingShouldReturnFalseIfBraintreeIdEmpty() {
        assertFalse(unit.isStoreInVaultForCardVaulting(StringUtils.EMPTY));
    }

    @Test
    public void getStoreInVaultForCardVaultingShouldReturnTrue() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isStoreInVault()).thenReturn(true);
        assertTrue(unit.isStoreInVaultForCardVaulting(BRAINTREE_CUSTOMER_ID));
    }

    @Test
    public void shouldGetCreditCardStatementName() {
        when(configuration.getString(BRAINTREE_DISPLAY_NAME)).thenReturn(CREDIT);
        assertEquals(CREDIT, unit.getBrainTreeDisplayName());
    }

    @Test
    public void getStoreInVaultForCardVaultingShouldReturnFalse() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isStoreInVault()).thenReturn(false);
        assertFalse(unit.isStoreInVaultForCardVaulting(BRAINTREE_CUSTOMER_ID));
    }

    @Test
    public void shouldGetSettlementConfigParameter() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isSubmitForSettlement()).thenReturn(true);
        assertTrue(unit.isSubmitForSettlement());
    }

    @Test
    public void shouldGetExpireBetweenByDefaultOne() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.getExpireBetween()).thenReturn(ONE);
        assertEquals(ONE, unit.getBrainTreeCreditCartExpireBetween());
    }

    @Test
    public void shouldGetBrainTreeCreditExpireOnAddingValidationByDefaultTrue() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.isExpireOnAdding()).thenReturn(true);
        assertTrue(unit.isBrainTreeCreditExpireOnAddingValidation());
    }

    @Test
    public void shouldGetVenmoEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(venmoConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isVenmoEnabled());
    }

    @Test
    public void shouldGetUsBankAccountEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(achConfigurationModel.isEnabled()).thenReturn(true);
        assertTrue(unit.isUsBankAccountEnabled());
    }

    @Test
    public void shouldGetUsBankAccountMerchantName() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(achConfigurationModel.getMerchantName()).thenReturn(MERCHANT_NAME);
        assertEquals(MERCHANT_NAME, unit.getUsBankAccountMerchantName());
    }

    @Test
    public void shouldGetVerifyCard() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.isVerifyCard()).thenReturn(true);
        assertTrue(unit.isVerifyCard());
    }

    @Test
    public void shouldGetAcceptedPaymentMethodImagesNoAcceptedPaymentMethods() {
        final Map<String, String> acceptedPaymentMethodImagesExpected = new HashMap<>();

        final Map<String, String> acceptedPaymentMethodImagesActual = unit
                .getAcceptedPaymentMethodImages(BRAINTREE_ACCEPTED_CREDIT_CARD_PAYMENT_METHODS);

        assertEquals(acceptedPaymentMethodImagesExpected, acceptedPaymentMethodImagesActual);
    }

    @Test
    public void shouldGetAcceptedPaymentMethodImagesOneAcceptedPaymentMethods() {
        final Map<String, String> acceptedPaymentMethodImagesExpected = new HashMap<>();
        acceptedPaymentMethodImagesExpected.put(PAYMENT_METHOD1, IMAGE_LINK1);
        when(configuration.getString(BRAINTREE_ACCEPTED_PAYMENT_METHODS))
                .thenReturn(PAYMENT_METHODS_STRING_ONE_PAYMENT);
        when(configuration.getString(BRAINTREE_IMAGES_PREFIX + PAYMENT_METHOD1)).thenReturn(IMAGE_LINK1);

        final Map<String, String> acceptedPaymentMethodImagesActual = unit
                .getAcceptedPaymentMethodImages(BRAINTREE_ACCEPTED_PAYMENT_METHODS);

        assertEquals(acceptedPaymentMethodImagesExpected, acceptedPaymentMethodImagesActual);
    }

    @Test
    public void shouldGetAcceptedPaymentMethodImagesMoreThanOneAcceptedPaymentMethods() {
        final Map<String, String> acceptedPaymentMethodImagesExpected = new HashMap<>();
        acceptedPaymentMethodImagesExpected.put(PAYMENT_METHOD1, IMAGE_LINK1);
        acceptedPaymentMethodImagesExpected.put(PAYMENT_METHOD2, IMAGE_LINK2);
        when(configuration.getString(BRAINTREE_ACCEPTED_PAYMENT_METHODS))
                .thenReturn(PAYMENT_METHODS_STRING_MORE_THAN_ONE_PAYMENT);
        when(configuration.getString(BRAINTREE_IMAGES_PREFIX + PAYMENT_METHOD1)).thenReturn(IMAGE_LINK1);
        when(configuration.getString(BRAINTREE_IMAGES_PREFIX + PAYMENT_METHOD2)).thenReturn(IMAGE_LINK2);

        final Map<String, String> acceptedPaymentMethodImagesActual = unit
                .getAcceptedPaymentMethodImages(BRAINTREE_ACCEPTED_PAYMENT_METHODS);

        assertEquals(acceptedPaymentMethodImagesExpected, acceptedPaymentMethodImagesActual);
    }

    @Test
    public void shouldNotGetAcceptedPaymentMethodImages() {
        final Map<String, String> acceptedPaymentMethodImagesExpected = new HashMap<>();
        when(configuration.getString(BRAINTREE_ACCEPTED_PAYMENT_METHODS))
                .thenReturn(PAYMENT_METHODS_STRING_MORE_THAN_ONE_PAYMENT);
        when(configuration.getString(BRAINTREE_IMAGES_PREFIX + PAYMENT_METHOD1)).thenReturn("");
        when(configuration.getString(BRAINTREE_IMAGES_PREFIX + PAYMENT_METHOD2)).thenReturn("");

        final Map<String, String> acceptedPaymentMethodImagesActual = unit
                .getAcceptedPaymentMethodImages(BRAINTREE_ACCEPTED_PAYMENT_METHODS);

        assertEquals(acceptedPaymentMethodImagesExpected, acceptedPaymentMethodImagesActual);
    }

    @Test
    public void shouldGetBackofficeSearchLimit() {
        when(configuration.getInt(BRAINTREE_SEARCH_LIMIT, 300)).thenReturn(ONE);
        assertEquals(ONE, unit.getBackofficeSearchLimit());
    }

    @Test
    public void shouldGetBillingAgreementDescription() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.getBillingAgreementText()).thenReturn(BILLING_AGREEMENT_TEXT);
        assertEquals(BILLING_AGREEMENT_TEXT, unit.getBillingAgreementDescription());
    }

    @Test
    public void shouldGetBrainTreeChannel() {
        when(configuration.getString(BRAINTREE_KEY)).thenReturn(BRAINTREE_KEY);
        when(configuration.getString(BRAINTREE_CHANNEL_NAME)).thenReturn(BRAINTREE_CHANNEL_NAME);

        final String result = unit.getBrainTreeChannel();

        assertEquals(HYBRIS_BT, result);
    }

    @Test
    public void shouldGetBrainTreeLocale() {
        when(configuration.getString(BRAINTREE_LOCALE)).thenReturn(US);
        assertEquals(US, unit.getBrainTreeLocale());
    }

    @Test
    public void getDisableFundingShouldReturnCorrectValueForAccountPage() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.getDisableFunding()).thenReturn(StringUtils.EMPTY);
        assertEquals(BRAINTREE_DISABLE_FUNDING_ON_MY_ACCOUNT, unit.getDisableFunding(
                BraintreePageType.ACCOUNT));
    }

    @Test
    public void getDisableFundingShouldReturnCardIfChangePaymentButtonEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.getDisableFunding()).thenReturn(StringUtils.EMPTY);
        when(payPalConfigurationModel.isChangePaymentMethodButton()).thenReturn(true);
        assertEquals(CARD_FUNDING_SOURCE, unit.getDisableFunding(
                BraintreePageType.MARK));
    }

    @Test
    public void getDisableFundingShouldReturnCreditCardPayLaterForMyAccount() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        doReturn(CREDIT.toLowerCase()).when(unit).getPayPalDisableFunding();

        final String result = unit.getDisableFunding(BraintreePageType.ACCOUNT);

        assertEquals(DISABLE_FUNDING, result);
        verify(unit).getPayPalDisableFunding();
    }

    @Test
    public void shouldGetCurrencyMerchantAccountId() {
        final CurrencyModel currencyModel = mock(CurrencyModel.class);

        when(commonI18NService.getCurrentCurrency()).thenReturn(currencyModel);
        when(currencyModel.getIsocode()).thenReturn(ISO_CODE);
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getMerchantAccountId()).thenReturn(merchantAccountIds);

        assertEquals(MERCHANT_ACCOUNT_ID, unit.getCurrencyMerchantAccountId());

        verify(commonI18NService).getCurrentCurrency();
        verify(currencyModel).getIsocode();
        verify(pluginConfigurationModel).getBraintreeGeneralConfiguration();
        verify(generalConfigurationModel).getMerchantAccountId();
    }

    @Test
    public void shouldGetEndpointURL() {
        when(configuration.getString(B2C_ENDPOINT_URL_PROPERTY)).thenReturn(URL);
        assertEquals(URL, unit.getEndpointURL());
    }

    @Test
    public void shouldGetSandboxEnvironment() {
        when(configuration.getString(BRAINTREE_ENVIRONMENT)).thenReturn(ENVIRONMENT_SANDBOX);
        assertEquals(Environment.SANDBOX, unit.getEnvironmentType());
    }

    @Test
    public void shouldGetDevelopmentEnvironment() {
        when(configuration.getString(BRAINTREE_ENVIRONMENT)).thenReturn(ENVIRONMENT_DEVELOPMENT);
        assertEquals(Environment.DEVELOPMENT, unit.getEnvironmentType());
    }

    @Test
    public void shouldGetEnvironmentTypeName() {
        final Environment environment = mock(Environment.class);

        doReturn(environment).when(unit).getEnvironmentType();
        when(environment.getEnvironmentName()).thenReturn(ENVIRONMENT_SANDBOX);
        assertEquals(ENVIRONMENT_SANDBOX, unit.getEnvironmentTypeName());

        verify(unit).getEnvironmentType();
        verify(environment).getEnvironmentName();
    }

    @Test
    public void shouldGetGooglePayMerchantId() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(googlePayConfigurationModel.getMerchantId()).thenReturn(UID);
        assertEquals(UID, unit.getGooglePayMerchantId());
    }

    @Test
    public void shouldGetGooglePayCountryCode() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(googlePayConfigurationModel.getSellerCountryCode()).thenReturn(US);
        assertEquals(US, unit.getGooglePayCountryCode());
    }

    @Test
    public void shouldGetHybrisBuildApiVersion() {
        when(configuration.getString(HYBRIS_BUILD_API_VERSION)).thenReturn(String.valueOf(ONE));
        assertEquals(ONE, unit.getHybrisBuildApiVersion().intValue());
        verify(configuration).getString(HYBRIS_BUILD_API_VERSION);
    }

    @Test
    public void apiVersionLengthIsNull() {
        when(configuration.getString(HYBRIS_BUILD_API_VERSION)).thenReturn(String.valueOf(" "));
        assertNull(unit.getHybrisBuildApiVersion());
        verify(configuration).getString(HYBRIS_BUILD_API_VERSION);
    }

    @Test
    public void apiVersionIsNotNumeric() {
        when(configuration.getString(HYBRIS_BUILD_API_VERSION)).thenReturn(String.valueOf(KEY));
        assertNull(unit.getHybrisBuildApiVersion());
        verify(configuration).getString(HYBRIS_BUILD_API_VERSION);
    }

    @Test
    public void shouldNotGetHybrisBuildApiVersion() {
        when(configuration.getString(HYBRIS_BUILD_API_VERSION)).thenReturn("");
        assertNull(unit.getHybrisBuildApiVersion());
        verify(configuration).getString(HYBRIS_BUILD_API_VERSION);
    }

    @Test
    public void shouldGetIntent() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(payPalConfigurationModel.getIntent()).thenReturn(BraintreeIntent.SALE);
        assertEquals(BraintreeIntent.SALE.getCode().toLowerCase(), unit.getIntent());
    }

    @Test
    public void shouldGetMerchantAccountIdByCurrentSiteNameAndCurrency() {
        // given
        final CurrencyModel currencyModel = mock(CurrencyModel.class);
        when(commonI18NService.getCurrentCurrency()).thenReturn(currencyModel);
        when(currencyModel.getIsocode()).thenReturn(ISO_CODE);
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();

        // when
        final String merchantAccountIdActual = unit
                .getMerchantAccountIdForCurrentSiteAndCurrency();

        // then
        assertEquals(MERCHANT_ACCOUNT_ID, merchantAccountIdActual);
    }

    @Test
    public void shouldGetMerchantAccountIdByCurrentSiteNameAndCurrencyIsoCode() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();

        // when
        final String merchantAccountIdActual = unit
                .getMerchantAccountIdForCurrentSiteAndCurrencyIsoCode(ISO_CODE);

        // then
        assertEquals(MERCHANT_ACCOUNT_ID, merchantAccountIdActual);
    }

    @Test
    public void shouldGetMerchantAccountIdForCurrentSiteAndCurrencyIsoCode() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getMerchantAccountId()).thenReturn(merchantAccountIds);

        final String result = unit.getMerchantAccountIdForCurrentSiteAndCurrencyIsoCode(ISO_CODE);

        assertEquals(MERCHANT_ACCOUNT_ID, result);
        verify(generalConfigurationModel).getMerchantAccountId();
    }

    @Test
    public void shouldGetBrainTreePluginConfiguration() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final BraintreePluginConfigurationModel configurationModel = mock(BraintreePluginConfigurationModel.class);

        when(baseStoreService.getCurrentBaseStore()).thenReturn(baseStoreModel);
        when(baseStoreModel.getBraintreePluginConfiguration()).thenReturn(configurationModel);

        final BraintreePluginConfigurationModel result = unit.getBrainTreePluginConfiguration();

        assertEquals(configurationModel, result);

        verify(baseStoreService).getCurrentBaseStore();
        verify(baseStoreModel).getBraintreePluginConfiguration();
    }

    @Test(expected = BrainTreePluginConfigurationNotFound.class)
    public void shouldThrowBrainTreePluginConfigurationNotFoundExceptionBecauseBaseStoreModelIsNull() {
        when(baseStoreService.getCurrentBaseStore()).thenReturn(null);

        unit.getBrainTreePluginConfiguration();

        verify(baseStoreService).getCurrentBaseStore();
    }

    @Test(expected = BrainTreePluginConfigurationNotFound.class)
    public void shouldThrowBrainTreePluginConfigurationNotFoundExceptionBecauseBraintreePluginConfigurationIsNull() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);

        when(baseStoreService.getCurrentBaseStore()).thenReturn(baseStoreModel);
        when(baseStoreModel.getBraintreePluginConfiguration()).thenReturn(null);

        unit.getBrainTreePluginConfiguration();

        verify(baseStoreService).getCurrentBaseStore();
        verify(baseStoreModel).getBraintreePluginConfiguration();
    }

    @Test
    public void shouldGetMerchantAccountIdForSiteAndCurrencyIsoCode() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final BaseSiteModel baseSiteModel = mock(BaseSiteModel.class);
        final List<BaseStoreModel> baseStoreModels = Arrays.asList(baseStoreModel);

        when(baseSiteService.getBaseSiteForUID(UID)).thenReturn(baseSiteModel);
        when(baseSiteModel.getStores()).thenReturn(baseStoreModels);
        when(baseStoreModel.getBraintreePluginConfiguration()).thenReturn(pluginConfigurationModel);
        when(pluginConfigurationModel.getBraintreeGeneralConfiguration()).thenReturn(generalConfigurationModel);
        when(generalConfigurationModel.getMerchantAccountId()).thenReturn(merchantAccountIds);

        final String result = unit.getMerchantAccountIdForSiteAndCurrencyIsoCode(UID, ISO_CODE);

        assertEquals(MERCHANT_ACCOUNT_ID, result);
        verify(baseSiteService).getBaseSiteForUID(UID);
        verify(baseSiteModel).getStores();
        verify(baseStoreModel).getBraintreePluginConfiguration();
        verify(pluginConfigurationModel).getBraintreeGeneralConfiguration();
        verify(generalConfigurationModel).getMerchantAccountId();
    }

    @Test(expected = BrainTreePluginConfigurationNotFound.class)
    public void shouldThrowBrainTreePluginConfigurationNotFound() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final BaseSiteModel baseSiteModel = mock(BaseSiteModel.class);
        final List<BaseStoreModel> baseStoreModels = Arrays.asList(baseStoreModel);

        when(baseSiteService.getBaseSiteForUID(UID)).thenReturn(baseSiteModel);
        when(baseSiteModel.getStores()).thenReturn(baseStoreModels);
        when(baseStoreModel.getBraintreePluginConfiguration()).thenReturn(null);

        unit.getMerchantAccountIdForSiteAndCurrencyIsoCode(UID, ISO_CODE);
    }

    @Test
    public void shouldGetUserAction() {
        when(configuration.getString(BRAINTREE_USER_ACTION)).thenReturn(USER_ACTION);
        assertEquals(USER_ACTION, unit.getUserAction());
    }

    @Test
    public void shouldGetSrcSdkUrl() {
        when(configuration.getString(BRAINTREE_SRC_SDK_URL)).thenReturn(URL);
        assertEquals(URL, unit.getSrcSdkUrl());
    }

    @Test
    public void shouldGetSrcImgUr() {
        when(configuration.getString(BRAINTREE_SRC_IMG_URL)).thenReturn(URL);
        assertEquals(URL, unit.getSrcImgUrl());
    }

    @Test
    public void shouldGetVenmoProfileId() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(venmoConfigurationModel.getProfileId()).thenReturn(UID);
        assertEquals(UID, unit.getVenmoProfileId());
    }

    @Test
    public void shouldGetPayPalConnectAddPaymentMethodFlow() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(connectWithPayPalConfigurationModel.isAddPaymentMethodFlow()).thenReturn(true);
        assertTrue(unit.isPayPalConnectAddPaymentMethodFlow());
    }

    @Test
    public void shouldGetConnectWithPayPalEnabled() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(connectWithPayPalConfigurationModel.isEnable()).thenReturn(true);
        assertTrue(unit.isConnectWithPayPalEnabled());
    }

    @Test
    public void shouldGetEnableLoginViaPayPalToTheExistingUser() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(connectWithPayPalConfigurationModel.isLinkUserAccount()).thenReturn(true);
        assertTrue(unit.isEnableLoginViaPayPalToTheExistingUser());
    }

    @Test
    public void shouldGetPayPalLippAdditionalSecurityEnable() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(connectWithPayPalConfigurationModel.isLippAdditionalSecurity()).thenReturn(true);
        assertTrue(unit.isPayPalLippAdditionalSecurityEnable());
    }

    @Test
    public void shouldGetBraintreeVerifyFlow() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(hostedFieldsConfigurationModel.isReverify()).thenReturn(true);
        assertTrue(unit.isBraintreeVerifyFlow());
    }

    @Test
    public void shouldGetRestrictionPaymentMethodRemovalEnable() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.isRestrictionOfPaymentMethodRemoval()).thenReturn(true);
        assertTrue(unit.isRestrictionPaymentMethodRemovalEnable());
    }

    @Test
    public void shouldGetRestrictionPaymentMethodRemovalExpiration() {
        doReturn(pluginConfigurationModel).when(unit).getBrainTreePluginConfiguration();
        when(generalConfigurationModel.getRestrictionOfPaymentMethodRemovalExpiration()).thenReturn(ONE);
        assertEquals(ONE, unit.getRestrictionPaymentMethodRemovalExpiration());
    }

    @Test
    public void shouldGetBaseSiteForPayPalConfigurationId() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final List<BaseStoreModel> baseStoreModels = Arrays.asList(baseStoreModel);
        final BaseSiteModel baseSiteModel = mock(BaseSiteModel.class);
        final List<BaseSiteModel> baseSiteModels = Arrays.asList(baseSiteModel);

        when(brainTreeBaseStoreDao.findBaseStoresByPayPalConfiguration(UID)).thenReturn(baseStoreModels);
        when(baseStoreModel.getCmsSites()).thenReturn(baseSiteModels);

        final Optional<BaseSiteModel> result = unit.getBaseSiteForPayPalConfigurationId(UID);

        assertEquals(baseSiteModel, result.get());
        verify(brainTreeBaseStoreDao).findBaseStoresByPayPalConfiguration(UID);
        verify(baseStoreModel).getCmsSites();
    }

    @Test
    public void shouldGetBaseSiteForGeneralConfigurationId() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final List<BaseStoreModel> baseStoreModels = Arrays.asList(baseStoreModel);
        final BaseSiteModel baseSiteModel = mock(BaseSiteModel.class);
        final List<BaseSiteModel> baseSiteModels = Arrays.asList(baseSiteModel);

        when(brainTreeBaseStoreDao.findBaseStoresByGeneralConfiguration(UID)).thenReturn(baseStoreModels);
        when(baseStoreModel.getCmsSites()).thenReturn(baseSiteModels);

        final Optional<BaseSiteModel> result = unit.getBaseSiteForGeneralConfigurationId(UID);

        assertEquals(baseSiteModel, result.get());
        verify(brainTreeBaseStoreDao).findBaseStoresByGeneralConfiguration(UID);
        verify(baseStoreModel).getCmsSites();
    }

    @Test
    public void shouldGetBaseStoreForGeneralConfigurationId() {
        final BaseStoreModel baseStoreModel = mock(BaseStoreModel.class);
        final List<BaseStoreModel> baseStoreModels = Arrays.asList(baseStoreModel);

        when(brainTreeBaseStoreDao.findBaseStoresByPluginConfiguration(pluginConfigurationModel)).thenReturn(baseStoreModels);

        final List<BaseStoreModel> result = unit.getBaseStoresByPluginConfiguration(pluginConfigurationModel);

        assertEquals(baseStoreModel, result.get(0));
        verify(brainTreeBaseStoreDao).findBaseStoresByPluginConfiguration(pluginConfigurationModel);
    }

    @Test
    public void shouldGetPayPalConnectScript() {
        when(configuration.getString(PAYPAL_CONNECT_SCRIPT)).thenReturn(CONNECT_SCRIPT);
        assertEquals(CONNECT_SCRIPT, unit.getPayPalConnectScript());
    }

    @Test
    public void shouldGetPayPalConnectScopes() {
        when(configuration.getString(PAYPAL_CONNECT_SCOPES)).thenReturn(CONNECT_SCOPES);
        assertEquals(CONNECT_SCOPES, unit.getPayPalConnectScopes());
    }

    @Test
    public void shouldGetPayPalConnectResponseType() {
        when(configuration.getString(PAYPAL_CONNECT_RESPONSE_TYPE)).thenReturn(CONNECT_RESPONSE_TYPE);
        assertEquals(CONNECT_RESPONSE_TYPE, unit.getPayPalConnectResponseType());
    }

    @Test
    public void shouldGetClientID() {
        when(configuration.getString(CLIENT_ID)).thenReturn(UID);
        assertEquals(UID, unit.getClientID());
    }

    @Test
    public void shouldGetSecretKey() {
        when(configuration.getString(SECRET_KEY)).thenReturn(KEY);
        assertEquals(KEY, unit.getSecretKey());
    }

    @Test
    public void shouldGetPayPalApiUrl() {
        when(configuration.getString(PAYPAL_API_URL)).thenReturn(URL);
        assertEquals(URL, unit.getPayPalApiUrl());
    }

}
