package com.braintree.customersupportbackoffice.facade.impl;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintree.facade.BrainTreeConnectWithPayPalFacade;
import com.braintree.method.BrainTreePaymentService;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.core.model.BraintreeGeneralConfigurationModel;
import de.hybris.platform.core.model.BraintreePluginConfigurationModel;
import de.hybris.platform.payment.AdapterException;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import de.hybris.platform.store.BaseStoreModel;
import org.apache.commons.configuration.Configuration;
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.Arrays;
import java.util.List;

import static com.braintree.constants.BraintreeConstants.CLIENT_ID;
import static com.braintree.constants.BraintreeConstants.SECRET_KEY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_MERCHANT_ID;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_PUBLIC_KEY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_PRIVATE_KEY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ENVIRONMENT;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;

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

    private static final String MERCHANT_ID = "MERCHANT_ID";
    private static final String PUBLIC_KEY = "PUBLIC_KEY";
    private static final String PRIVATE_KEY = "PRIVATE_KEY";
    private static final String ENVIRONMENT = "ENVIRONMENT";
    private static final String PONG = "pong";
    private static final String BASE_STORE = "BASE_STORE";
    private static final String ID = "ID";
    private static final String KEY = "KEY";
    private static final String TOKEN = "TOKEN";

    @Mock
    private Configuration configuration;

    @Mock
    private ConfigurationService configurationService;
    @Mock
    private BrainTreePaymentService brainTreePaymentService;
    @Mock
    private BrainTreeConfigService brainTreeConfigService;
    @Mock
    private BrainTreeConnectWithPayPalFacade connectWithPayPalFacade;

    @Spy
    @InjectMocks
    private DefaultBraintreeCheckConnectionFacade unit;

    @Before
    public void setUp() {
        when(configurationService.getConfiguration()).thenReturn(configuration);
    }

    @Test
    public void shouldGetMerchantIDPresented() {
        when(configuration.getString(BRAINTREE_MERCHANT_ID)).thenReturn(MERCHANT_ID);

        assertTrue(unit.isMerchantIDPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(BRAINTREE_MERCHANT_ID);
    }

    @Test
    public void shouldGetPublicKeyPresented() {
        when(configuration.getString(BRAINTREE_PUBLIC_KEY)).thenReturn(PUBLIC_KEY);

        assertTrue(unit.isPublicKeyPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(BRAINTREE_PUBLIC_KEY);
    }

    @Test
    public void shouldGetPrivateKeyPresented() {
        when(configuration.getString(BRAINTREE_PRIVATE_KEY)).thenReturn(PRIVATE_KEY);

        assertTrue(unit.isPrivateKeyPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(BRAINTREE_PRIVATE_KEY);
    }

    @Test
    public void shouldGetEnvironmentPresented() {
        when(configuration.getString(BRAINTREE_ENVIRONMENT)).thenReturn(ENVIRONMENT);

        assertTrue(unit.isEnvironmentPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(BRAINTREE_ENVIRONMENT);
    }

    @Test
    public void shouldGetCanCheckConnectWithBraintree() {
        doReturn(true).when(unit).isMerchantIDPresented();
        doReturn(true).when(unit).isPublicKeyPresented();
        doReturn(true).when(unit).isPrivateKeyPresented();
        doReturn(true).when(unit).isEnvironmentPresented();

        assertTrue(unit.canCheckConnectWithBraintree());

        verify(unit).isMerchantIDPresented();
        verify(unit).isPublicKeyPresented();
        verify(unit).isPrivateKeyPresented();
        verify(unit).isEnvironmentPresented();
    }

    @Test
    public void shouldReturnTrueIsBraintreePingPresented() {
        when(brainTreePaymentService.getBraintreePing()).thenReturn(PONG);
        assertTrue(unit.isBraintreePingPresented());
        verify(brainTreePaymentService).getBraintreePing();
    }

    @Test
    public void shouldReturnFalseIsBraintreePingPresented() {
        when(brainTreePaymentService.getBraintreePing()).thenReturn("");
        assertFalse(unit.isBraintreePingPresented());
        verify(brainTreePaymentService).getBraintreePing();
    }

    @Test
    public void shouldCatchExceptionAndReturnFalse() {
        when(brainTreePaymentService.getBraintreePing()).thenThrow(new AdapterException(""));
        assertFalse(unit.isBraintreePingPresented());
    }

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

        when(brainTreeConfigService.getBaseStoresByPluginConfiguration(pluginConfiguration)).thenReturn(baseStoreModels);
        when(baseStoreModel.getName()).thenReturn(BASE_STORE);

        final List<String> result = unit.getBaseStoreNames(pluginConfiguration);

        assertEquals(BASE_STORE, result.stream().findFirst().get());
        verify(brainTreeConfigService).getBaseStoresByPluginConfiguration(pluginConfiguration);
        verify(baseStoreModel).getName();
    }

    @Test
    public void shouldGetPayPalClientIdPresented() {
        when(configuration.getString(CLIENT_ID)).thenReturn(ID);

        assertTrue(unit.isPayPalClientIdPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(CLIENT_ID);
    }

    @Test
    public void shouldGetPayPalSecretKeyPresented() {
        when(configuration.getString(SECRET_KEY)).thenReturn(KEY);

        assertTrue(unit.isPayPalSecretKeyPresented());
        verify(configurationService).getConfiguration();
        verify(configuration).getString(SECRET_KEY);
    }

    @Test
    public void shouldReturnTrueForCanCheckConnectWithPayPal() {
        doReturn(true).when(unit).isPayPalClientIdPresented();
        doReturn(true).when(unit).isPayPalSecretKeyPresented();

        assertTrue(unit.canCheckConnectWithPayPal());
    }

    @Test
    public void shouldReturnFalseBecausePayPalClientIdNotPresented() {
        doReturn(false).when(unit).isPayPalClientIdPresented();

        assertFalse(unit.canCheckConnectWithPayPal());
    }

    @Test
    public void shouldReturnFalseBecausePayPalSecretKeyNotPresented() {
        doReturn(true).when(unit).isPayPalClientIdPresented();
        doReturn(false).when(unit).isPayPalSecretKeyPresented();

        assertFalse(unit.canCheckConnectWithPayPal());
    }

    @Test
    public void shouldReturnTrueCanEstablishConnectWithPayPal() {
        when(connectWithPayPalFacade.getAccessToken()).thenReturn(TOKEN);
        assertTrue(unit.canEstablishConnectWithPayPal());
        verify(connectWithPayPalFacade).getAccessToken();
    }

    @Test
    public void shouldReturnFalseCanEstablishConnectWithPayPal() {
        when(connectWithPayPalFacade.getAccessToken()).thenReturn("");
        assertFalse(unit.canEstablishConnectWithPayPal());
        verify(connectWithPayPalFacade).getAccessToken();
    }

    @Test
    public void shouldCatchExceptionAndReturnFalseForCanEstablishConnectWithPayPal() {
        when(connectWithPayPalFacade.getAccessToken()).thenThrow(new AdapterException(""));
        assertFalse(unit.canEstablishConnectWithPayPal());
    }

}
