package com.justjournal.services;

import com.justjournal.Application;
import com.justjournal.model.EntryStatistic;
import com.justjournal.model.User;
import com.justjournal.repository.EntryRepository;
import com.justjournal.repository.EntryStatisticRepository;
import com.justjournal.repository.UserRepository;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.Collections;
import java.util.Iterator;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

/**
 * @author Lucas Holt
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class EntryStatisticsServiceTests {

    private static final String TEST_USER = "testuser";
    private static final int TEST_YEAR = 2003;

    @InjectMocks
    private EntryStatisticService entryStatisticService;

    @Mock
    private UserRepository userRepository;

    @Mock
    private EntryStatisticRepository entryStatisticRepository;

    @Mock
    private EntryRepository entryRepository;

    @Mock
    private EntryStatistic entryStatistic;

    @Mock
    private User user;


    @Before
    public void setupMock() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getEntryCounts() {
        when(entryStatisticRepository.findByUsernameOrderByYearDesc(TEST_USER)).thenReturn(Collections.singletonList(entryStatistic));
        when(entryStatistic.getUser()).thenReturn(user);
        when(entryStatistic.getCount()).thenReturn(1L);
        when(entryStatistic.getYear()).thenReturn(TEST_YEAR);
        when(user.getUsername()).thenReturn(TEST_USER);

        Observable<EntryStatistic> o = entryStatisticService.getEntryCounts(TEST_USER);
        final Iterable<EntryStatistic> myIterator = o.blockingIterable();


        assertNotNull(myIterator);

        Iterator<EntryStatistic> iterator = myIterator.iterator();
        assertTrue(iterator.hasNext());

        EntryStatistic es = iterator.next();

        verify(entryStatisticRepository, atLeastOnce()).findByUsernameOrderByYearDesc(TEST_USER);

        assertEquals(TEST_USER, es.getUser().getUsername());
        assertEquals(TEST_YEAR, es.getYear());
        assertEquals(1L, es.getCount());
    }


    @Test
    public void getEntryCount() {
        when(entryStatisticRepository.findByUsernameAndYear(TEST_USER, TEST_YEAR)).thenReturn(entryStatistic);
        when(entryStatistic.getUser()).thenReturn(user);
        when(entryStatistic.getCount()).thenReturn(1L);
        when(entryStatistic.getYear()).thenReturn(TEST_YEAR);
        when(user.getUsername()).thenReturn(TEST_USER);

        Maybe<EntryStatistic> o = entryStatisticService.getEntryCount(TEST_USER, TEST_YEAR);

        EntryStatistic es = o.blockingGet();
        verify(entryStatisticRepository, atLeastOnce()).findByUsernameAndYear(TEST_USER, TEST_YEAR);

        assertEquals(TEST_USER, es.getUser().getUsername());
        assertEquals(TEST_YEAR, es.getYear());
        assertEquals(1L, es.getCount());
    }

    @Test(expected = IllegalArgumentException.class)
    public void computeBadStartYear() {
        entryStatisticService.compute(user, 0, TEST_YEAR);
    }

    @Test(expected = IllegalArgumentException.class)
    public void computeBadEndYear() {
        entryStatisticService.compute(user, TEST_YEAR, 0);
    }

    /*   TODO: not working due to rxjava scheduler io multithreading.
    @Test
    public void computeSingle() {
        when(entryStatisticRepository.findByUserAndYear(user, TEST_YEAR + 1)).thenReturn(entryStatistic);
        when(user.getUsername()).thenReturn(TEST_USER);
        when(entryRepository.calendarCount(TEST_YEAR, TEST_USER)).thenReturn(1L);
        when(entryStatistic.getUser()).thenReturn(user);
        when(entryStatistic.getCount()).thenReturn(1L);
        when(entryStatistic.getYear()).thenReturn(TEST_YEAR);
        when(entryStatisticRepository.saveAndFlush(entryStatistic)).thenReturn(entryStatistic);

        TestObserver<EntryStatistic> testObserver = entryStatisticService.compute(user, TEST_YEAR, TEST_YEAR )
                .test().awaitDone(5, TimeUnit.SECONDS);

      //  testObserver.awaitTerminalEvent();
        verify(entryStatisticRepository, atLeastOnce()).findByUserAndYear(user, TEST_YEAR);
          verify(entryRepository, atLeastOnce()).calendarCount(TEST_YEAR, TEST_USER);

        testObserver
            .assertNoErrors()
            .assertValue(new Predicate<EntryStatistic>() {
                @Override
                public boolean test(final EntryStatistic entryStatistic) throws Exception {
                    return entryStatistic.getCount() == 1L ;
                }
            });
    }
             */

    // @Rule
    //  public TrampolineSchedulerRule rule = new TrampolineSchedulerRule();
}

@@ -537,24 +537,110 @@
 nnotations;%0A
+import org.mockito.junit.MockitoJUnit;%0Aimport org.mockito.runners.MockitoJUnitRunner;%0A
 import org.s
@@ -1007,120 +1007,33 @@
 ith(
-SpringJUnit4ClassRunner.class)%0A@SpringApplicationConfiguration(classes = Application.class)%0A@WebAppConfiguration
+MockitoJUnitRunner.class)
 %0Apub
@@ -1180,83 +1180,12 @@
 03;%0A
-%0A
     
-@InjectMocks%0A    private EntryStatisticService entryStatisticService;%0A
 %0A   
@@ -1362,36 +1362,43 @@
 pository;%0A%0A    @
+Inject
 Mock
+s
 %0A    private Ent
@@ -1400,32 +1400,39 @@
 e EntryStatistic
+Service
  entryStatistic;
@@ -1430,28 +1430,69 @@
 tatistic
-;%0A%0A    @Mock
+Service;%0A%0A%0A    private EntryStatistic entryStatistic;
 %0A    pri
@@ -1563,214 +1563,95 @@
     
-MockitoAnnotations.initMocks(this);%0A    %7D%0A%0A    @Test%0A    public void getEntryCounts() %7B%0A        when(entryStatisticRepository.findByUsernameOrderByYearDesc(TEST_USER)).thenReturn(Collections.singletonList(e
+user = new User();%0A        user.setUsername(TEST_USER);%0A%0A        entryStatistic = new E
 ntry
@@ -1659,17 +1659,17 @@
 tatistic
-)
+(
 );%0A     
@@ -1663,37 +1663,32 @@
 stic();%0A        
-when(
 entryStatistic.g
@@ -1686,38 +1686,24 @@
 atistic.
-g
+s
 etUser(
-)).thenReturn(
 user);%0A 
@@ -1701,37 +1701,32 @@
 (user);%0A        
-when(
 entryStatistic.g
@@ -1720,33 +1720,33 @@
 ryStatistic.
-g
+s
 etCount(
 )).thenRetur
@@ -1729,38 +1729,24 @@
 ic.setCount(
-)).thenReturn(
 1L);%0A       
@@ -1738,37 +1738,32 @@
 nt(1L);%0A        
-when(
 entryStatistic.g
@@ -1761,38 +1761,24 @@
 atistic.
-g
+s
 etYear(
-)).thenReturn(
 TEST_YEA
@@ -1789,61 +1789,191 @@
     
-    when(user.getUsername()).thenReturn(TEST_USER
+%7D%0A%0A    @Test%0A    public void getEntryCounts() %7B%0A        when(entryStatisticRepository.findByUsernameOrderByYearDesc(TEST_USER)).thenReturn(Collections.singletonList(entryStatistic)
 );%0A
-%0A
     
@@ -2745,231 +2745,8 @@
     
-when(entryStatistic.getUser()).thenReturn(user);%0A        when(entryStatistic.getCount()).thenReturn(1L);%0A        when(entryStatistic.getYear()).thenReturn(TEST_YEAR);%0A        when(user.getUsername()).thenReturn(TEST_USER);%0A
 %0A   

fix tests.