package uk.ac.ebi.quickgo.annotation.service.statistics;

import uk.ac.ebi.quickgo.annotation.model.Annotation;
import uk.ac.ebi.quickgo.annotation.model.AnnotationRequest;
import uk.ac.ebi.quickgo.rest.search.SearchService;
import uk.ac.ebi.quickgo.rest.search.query.QuickGOQuery;
import uk.ac.ebi.quickgo.rest.search.request.FilterRequest;
import uk.ac.ebi.quickgo.rest.search.request.converter.ConvertedFilter;
import uk.ac.ebi.quickgo.rest.search.request.converter.FilterConverter;
import uk.ac.ebi.quickgo.rest.search.request.converter.FilterConverterFactory;
import uk.ac.ebi.quickgo.rest.search.results.AggregateResponse;
import uk.ac.ebi.quickgo.rest.search.results.QueryResult;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Tests the behaviour of the {@link AnnotationStatisticsService} class.
 */
@RunWith(MockitoJUnitRunner.class)
public class AnnotationStatisticsServiceTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    private AnnotationStatisticsService statsService;
    private AnnotationRequest request;

    @Mock
    private FilterConverterFactory filterFactoryMock;

    @Mock
    private SearchService<Annotation> searchServiceMock;

    @Mock
    private StatsConverter statsConverterMock;

    @Mock
    private RequiredStatisticsProvider requiredStatisticsProvider;

    @Mock
    private QueryResult<Annotation> queryResult;

    @Mock
    private AggregateResponse aggregateResponse;

    @Mock
    private ConvertedFilter<QuickGOQuery> convertedFilter;

    @Before
    public void setUp() {
        request = new AnnotationRequest();

        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);

        when(searchServiceMock.findByQuery(any())).thenReturn(queryResult);
        when(queryResult.getAggregation()).thenReturn(aggregateResponse);
        when(filterFactoryMock.convert(any())).thenReturn(convertedFilter);
    }

    @Test
    public void nullFilterFactoryThrowsExceptionInConstructor() {
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Filter factory cannot be null");

        statsService = new AnnotationStatisticsService(null, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);
    }

    @Test
    public void nullSearchServiceThrowsExceptionInConstructor() {
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Search service cannot be null");

        statsService = new AnnotationStatisticsService(filterFactoryMock, null,
                statsConverterMock, requiredStatisticsProvider);
    }

    @Test
    public void nullStatsConverterThrowsExceptionInConstructor() {
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Stats request converter cannot be null");

        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                null, requiredStatisticsProvider);
    }

    @Test
    public void nullRequiredStatisticsProviderThrowsExceptionInConstructor() {
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Statistics provider cannot be null.");

        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, null);
    }

    @Test
    public void calculatingRequiredStatisticsForStandardUsageWithNullAnnotationThrowsException() {
        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Annotation request cannot be null");

        statsService.calculateForStandardUsage(null);
    }

    @Test
    public void requiredStatisticsProviderCalledForStandardUsageOnly() {
        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);
        request.setGeneProductId("A0A000");

        statsService.calculateForStandardUsage(request);

        verify(requiredStatisticsProvider).getStandardUsage();
    }

    @Test
    public void requiredStatisticsProviderCalledForStandardUsageWithGeneProductFiltering() {
        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);
        request.setGeneProductId("A0A000");

        statsService.calculateForStandardUsage(request);

        verify(requiredStatisticsProvider).getStandardUsageWithGeneProductFiltering();
    }

    @Test
    public void requiredStatisticsProviderCalledForDownloadUsageOnly() {
        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);
        request.setAspect("C");

        statsService.calculateForDownloadUsage(request);

        verify(requiredStatisticsProvider).getDownloadUsage();
    }

    @Test
    public void requiredStatisticsProviderCalledForDownloadUsageWithGeneProductFiltering() {
        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,
                statsConverterMock, requiredStatisticsProvider);
        request.setGeneProductId("A0A000");

        statsService.calculateForDownloadUsage(request);

        verify(requiredStatisticsProvider).getDownloadUsageWithGeneProductFiltering();
    }

    class TestFilterConverter implements FilterConverter<FilterRequest, QuickGOQuery> {

        @Override public ConvertedFilter<QuickGOQuery> transform(FilterRequest request) {
            return convertedFilter;
        }
    }
}

@@ -944,50 +944,8 @@
 ny;%0A
-import static org.mockito.Mockito.verify;%0A
 impo
@@ -980,16 +980,16 @@
 o.when;%0A
+
 %0A/**%0A * 
@@ -1276,47 +1276,8 @@
 ice;
-%0A    private AnnotationRequest request;
 %0A%0A  
@@ -1775,52 +1775,8 @@
 ) %7B%0A
-        request = new AnnotationRequest();%0A%0A
     
@@ -3794,32 +3794,32 @@
 not be null%22);%0A%0A
+
         statsSer
@@ -3867,1740 +3867,8 @@
  %7D%0A%0A
-    @Test%0A    public void requiredStatisticsProviderCalledForStandardUsageOnly() %7B%0A        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,%0A                statsConverterMock, requiredStatisticsProvider);%0A        request.setGeneProductId(%22A0A000%22);%0A%0A        statsService.calculateForStandardUsage(request);%0A%0A        verify(requiredStatisticsProvider).getStandardUsage();%0A    %7D%0A%0A    @Test%0A    public void requiredStatisticsProviderCalledForStandardUsageWithGeneProductFiltering() %7B%0A        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,%0A                statsConverterMock, requiredStatisticsProvider);%0A        request.setGeneProductId(%22A0A000%22);%0A%0A        statsService.calculateForStandardUsage(request);%0A%0A        verify(requiredStatisticsProvider).getStandardUsageWithGeneProductFiltering();%0A    %7D%0A%0A    @Test%0A    public void requiredStatisticsProviderCalledForDownloadUsageOnly() %7B%0A        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,%0A                statsConverterMock, requiredStatisticsProvider);%0A        request.setAspect(%22C%22);%0A%0A        statsService.calculateForDownloadUsage(request);%0A%0A        verify(requiredStatisticsProvider).getDownloadUsage();%0A    %7D%0A%0A    @Test%0A    public void requiredStatisticsProviderCalledForDownloadUsageWithGeneProductFiltering() %7B%0A        statsService = new AnnotationStatisticsService(filterFactoryMock, searchServiceMock,%0A                statsConverterMock, requiredStatisticsProvider);%0A        request.setGeneProductId(%22A0A000%22);%0A%0A        statsService.calculateForDownloadUsage(request);%0A%0A        verify(requiredStatisticsProvider).getDownloadUsageWithGeneProductFiltering();%0A    %7D%0A%0A
     

Remove tests that relied on too much mocking to set up.