package ru.goenglish.goenglish;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ru.goenglish.goenglish.api.Api;
import ru.goenglish.goenglish.dao.EventDao;
import ru.goenglish.goenglish.dao.entity.EventEntity;
import ru.goenglish.goenglish.mapper.impl.EventMapperImpl;
import ru.goenglish.goenglish.model.Event;
import ru.goenglish.goenglish.model.Response;
import ru.goenglish.goenglish.services.ScheduleService;
import ru.goenglish.goenglish.services.impl.ScheduleServiceImpl;
import ru.goenglish.goenglish.util.UnitTestResponseUtil;
import ru.goenglish.goenglish.util.UnitTestRxUtil;
import rx.Observable;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;

/**
 * Created by user on 14.05.2016.
 */
public class ScheduleServiceImplTest {

    private static final String FILIAL_PARAM = "some filial";

    private ScheduleService scheduleService;
    private Api apiMock;
    private EventDao daoMock;
    private UnitTestResponseUtil responseUtils;

    @Before
    public void setupScheduleService() {
        apiMock = mock(Api.class);
        daoMock = mock(EventDao.class);
        responseUtils = new UnitTestResponseUtil();
        scheduleService = new ScheduleServiceImpl(
                apiMock,
                daoMock,
                new EventMapperImpl(),
                new UnitTestRxUtil()
        );
    }

    @Test
    public void testLoadAndCacheEvents(){
        Response<List<Event>> fakeResponse = responseUtils.getFakeResponse();

        when(apiMock.getSchedule(anyString()))
                .thenReturn(Observable.just(fakeResponse));

        doNothing()
                .when(daoMock)
                .saveEventEntityList(anyListOf(EventEntity.class));

        scheduleService.loadAndCacheEvents(FILIAL_PARAM);
        Class<List<EventEntity>> listClass = (Class<List<EventEntity>>) (Class) List.class;
        ArgumentCaptor<List<EventEntity>> captor = ArgumentCaptor.forClass(listClass);

        //check that method was called 1 time with param FILIAL_PARAM
        verify(apiMock, times(1))
                .getSchedule(FILIAL_PARAM);


        verify(daoMock, times(1))
                .saveEventEntityList(captor.capture());

        //assert that sizes are same
        assertEquals(fakeResponse.getResult().size(), captor.getValue().size());

        List<EventEntity> daoParam = captor.getValue();
        List<Event> actualList = fakeResponse.getResult();
        for(int i = 0; i < actualList.size(); i ++){
            assertEquals(daoParam.get(i).getId(), actualList.get(i).getId());
            assertEquals(daoParam.get(i).getStartDate(), actualList.get(i).getStartDate());
            assertEquals(daoParam.get(i).getEndDate(), actualList.get(i).getEndDate());
            assertEquals(daoParam.get(i).getText(), actualList.get(i).getText());
            assertEquals(daoParam.get(i).getCourseName(), actualList.get(i).getCourseName());
            assertEquals(daoParam.get(i).getCourceId(), actualList.get(i).getCourceId());
            assertEquals(daoParam.get(i).getSubjectName(), actualList.get(i).getSubjectName());
            assertEquals(daoParam.get(i).getSubjectId(), actualList.get(i).getSubjectId());
            assertEquals(daoParam.get(i).getInfoForContacts(), actualList.get(i).getInfoForContacts());
            assertEquals(daoParam.get(i).getAudience(), actualList.get(i).getAudience());
            assertEquals(daoParam.get(i).getRemainingSeats(), actualList.get(i).getRemainingSeats());
            assertEquals(daoParam.get(i).getCost(), actualList.get(i).getCost());
            assertEquals(daoParam.get(i).getNumberSeats(), actualList.get(i).getNumberSeats());
            assertEquals(daoParam.get(i).getEmployeesIds(), actualList.get(i).getEmployeesIds());
            assertEquals(daoParam.get(i).getEmployeeName(), actualList.get(i).getEmployeeName());
            assertEquals(daoParam.get(i).getAlreadyCalculate(), actualList.get(i).getAlreadyCalculate());
            assertEquals(daoParam.get(i).getRecType(), actualList.get(i).getRecType());
            assertEquals(daoParam.get(i).getEventPid(), actualList.get(i).getEventPid());
            assertEquals(daoParam.get(i).getUrlC(), actualList.get(i).getUrlC());
            assertEquals(daoParam.get(i).getCalendarHidden(), actualList.get(i).getCalendarHidden());
            assertEquals(daoParam.get(i).getCalendarWrittenLinkDisable(), actualList.get(i).getCalendarWrittenLinkDisable());
            assertEquals(daoParam.get(i).getFilial(), actualList.get(i).getFilial());
            assertEquals(daoParam.get(i).getContactsIds(), actualList.get(i).getContactsIds());
            assertEquals(daoParam.get(i).getClassStatus(), actualList.get(i).getClassStatus());
        }
    }

    @Test
    public void testNullFilialParam(){
        when(apiMock.getSchedule(null))
                .thenReturn(Observable.just(null));
        scheduleService.loadAndCacheEvents(null);
        verify(apiMock, never()).getSchedule(null);
    }

    @Test
    public void testEmptyServerResponse() {
        when(apiMock.getSchedule(anyString()))
                .thenReturn(Observable.just(responseUtils.getFakeResponseWithEmptyList()));
        doNothing()
                .when(daoMock)
                .saveEventEntityList(anyListOf(EventEntity.class));
        scheduleService.loadAndCacheEvents(FILIAL_PARAM);

        Class<List<EventEntity>> listClass = (Class<List<EventEntity>>) (Class) List.class;
        ArgumentCaptor<List<EventEntity>> captor = ArgumentCaptor.forClass(listClass);

        verify(apiMock, times(1))
                .getSchedule(FILIAL_PARAM);

        verify(daoMock, never()).saveEventEntityList(captor.capture());
    }

}
