package com.braintree.daos.impl;

import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.core.model.BraintreePluginConfigurationModel;
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.FlexibleSearchService;
import de.hybris.platform.servicelayer.search.SearchResult;
import de.hybris.platform.store.BaseStoreModel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;

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

    private static final String FIND_BASESTORE_BY_PAYPALCONFIGURATION = "SELECT {pk} " +
            "FROM {BaseStore as bs " +
            "JOIN BraintreePluginConfiguration as pc ON {bs.braintreePluginConfiguration} = {pc.pk} " +
            "JOIN BraintreePayPalConfiguration as ppc ON {pc.braintreePayPalConfiguration} = {ppc.pk}} " +
            "WHERE {ppc.braintreePayPalConfigurationId} = ?braintreePayPalConfigurationId";

    private static final String FIND_BASE_STORE_BY_GENERAL_CONFIGURATION = "SELECT {pk} " +
            "FROM {BaseStore as bs " +
            "JOIN BraintreePluginConfiguration as pc ON {bs.braintreePluginConfiguration} = {pc.pk} " +
            "JOIN BraintreeGeneralConfiguration as ppc ON {pc.braintreeGeneralConfiguration} = {ppc.pk}} " +
            "WHERE {ppc.braintreeGeneralConfigurationId} = ?braintreeGeneralConfigurationId";

    private static final String FIND_BASE_STORES_BY_PLUGIN_CONFIGURATION = "SELECT {pk} " +
            "FROM {BaseStore as bs " +
            "JOIN BraintreePluginConfiguration as pc ON {bs.braintreePluginConfiguration} = {pc.pk}} " +
            "WHERE {pc.braintreePluginConfigurationId} = ?braintreePluginConfigurationId";

    private static final String PAYPAL_CONFIGURATION_ID = "configurationId";
    private static final String PAYPAL_CONFIGURATION_ID_KEY = "braintreePayPalConfigurationId";
    private static final String GENERAL_CONFIGURATION_ID = "generalConfigurationId";
    private static final String GENERAL_CONFIGURATION_KEY = "braintreeGeneralConfigurationId";
    private static final String PLUGIN_CONFIGURATION_ID = "pluginConfigurationId";
    private static final String PLUGIN_CONFIGURATION_KEY = "braintreePluginConfigurationId";

    @Mock
    private FlexibleSearchService flexibleSearchService;

    @InjectMocks
    private DefaultBrainTreeBaseStoreDao unit;

    @Captor
    private ArgumentCaptor<FlexibleSearchQuery> flexibleSearchQueryCaptor;
    @Mock
    private SearchResult<BaseStoreModel> searchResult;
    @Mock
    private BaseStoreModel baseStore;

    @Test
    public void shouldFindBaseStoreByPayPalConfiguration() {
        when(flexibleSearchService.<BaseStoreModel>search(any(FlexibleSearchQuery.class))).thenReturn(searchResult);
        when(searchResult.getResult()).thenReturn(List.of(baseStore));

        List<BaseStoreModel> baseStoresByPayPalConfiguration = unit.findBaseStoresByPayPalConfiguration(PAYPAL_CONFIGURATION_ID);

        assertTrue(baseStoresByPayPalConfiguration.contains(baseStore));
        verify(flexibleSearchService).<BaseStoreModel>search(flexibleSearchQueryCaptor.capture());
        FlexibleSearchQuery flexibleSearchQuery = flexibleSearchQueryCaptor.getValue();
        assertEquals(FIND_BASESTORE_BY_PAYPALCONFIGURATION, flexibleSearchQuery.getQuery());
        Map<String, Object> queryParameters = flexibleSearchQuery.getQueryParameters();
        assertTrue(queryParameters.containsKey(PAYPAL_CONFIGURATION_ID_KEY));
        assertEquals(PAYPAL_CONFIGURATION_ID, queryParameters.get(PAYPAL_CONFIGURATION_ID_KEY));
    }

    @Test
    public void shouldFindBaseStoreByGeneralConfiguration() {
        when(flexibleSearchService.<BaseStoreModel>search(any(FlexibleSearchQuery.class))).thenReturn(searchResult);
        when(searchResult.getResult()).thenReturn(List.of(baseStore));

        List<BaseStoreModel> baseStoresByPayPalConfiguration = unit.findBaseStoresByGeneralConfiguration(GENERAL_CONFIGURATION_ID);

        assertTrue(baseStoresByPayPalConfiguration.contains(baseStore));
        verify(flexibleSearchService).<BaseStoreModel>search(flexibleSearchQueryCaptor.capture());
        FlexibleSearchQuery flexibleSearchQuery = flexibleSearchQueryCaptor.getValue();
        assertEquals(FIND_BASE_STORE_BY_GENERAL_CONFIGURATION, flexibleSearchQuery.getQuery());
        Map<String, Object> queryParameters = flexibleSearchQuery.getQueryParameters();
        assertTrue(queryParameters.containsKey(GENERAL_CONFIGURATION_KEY));
        assertEquals(GENERAL_CONFIGURATION_ID, queryParameters.get(GENERAL_CONFIGURATION_KEY));
    }

    @Test
    public void shouldFindBaseStoreByPluginConfiguration() {
        final BraintreePluginConfigurationModel pluginConfiguration = mock(BraintreePluginConfigurationModel.class);

        when(pluginConfiguration.getBraintreePluginConfigurationId()).thenReturn(PLUGIN_CONFIGURATION_ID);
        when(flexibleSearchService.<BaseStoreModel>search(any(FlexibleSearchQuery.class))).thenReturn(searchResult);
        when(searchResult.getResult()).thenReturn(List.of(baseStore));

        List<BaseStoreModel> baseStoresByPayPalConfiguration = unit.findBaseStoresByPluginConfiguration(pluginConfiguration);

        assertTrue(baseStoresByPayPalConfiguration.contains(baseStore));
        verify(flexibleSearchService).<BaseStoreModel>search(flexibleSearchQueryCaptor.capture());
        FlexibleSearchQuery flexibleSearchQuery = flexibleSearchQueryCaptor.getValue();
        assertEquals(FIND_BASE_STORES_BY_PLUGIN_CONFIGURATION, flexibleSearchQuery.getQuery());
        Map<String, Object> queryParameters = flexibleSearchQuery.getQueryParameters();
        assertTrue(queryParameters.containsKey(PLUGIN_CONFIGURATION_KEY));
        assertEquals(PLUGIN_CONFIGURATION_ID, queryParameters.get(PLUGIN_CONFIGURATION_KEY));
    }

}