package uk.ivanc.archimvvm;

import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import java.util.Collections;
import java.util.List;

import okhttp3.ResponseBody;
import retrofit2.Response;
import retrofit2.adapter.rxjava.HttpException;
import rx.Observable;
import rx.schedulers.Schedulers;
import uk.ivanc.archimvvm.model.GithubService;
import uk.ivanc.archimvvm.model.Repository;
import uk.ivanc.archimvvm.util.MockModelFabric;
import uk.ivanc.archimvvm.viewmodel.MainViewModel;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class MainViewModelTest {

    GithubService githubService;
    ArchiApplication application;
    MainViewModel mainViewModel;
    MainViewModel.DataListener dataListener;

    @Before
    public void setUp() {
        githubService = mock(GithubService.class);
        dataListener = mock(MainViewModel.DataListener.class);
        application = (ArchiApplication) RuntimeEnvironment.application;
        // Mock the retrofit service so we don't call the API directly
        application.setGithubService(githubService);
        // Change the default subscribe schedulers so all observables
        // will now run on the same thread
        application.setDefaultSubscribeScheduler(Schedulers.immediate());
        mainViewModel = new MainViewModel(application, dataListener);
    }


    @Test
    public void shouldSearchUsernameWithRepos() {
        String username = "usernameWithRepos";
        TextView textView = new TextView(application);
        textView.setText(username);
        List<Repository> mockRepos = MockModelFabric.newListOfRepositories(10);
        doReturn(rx.Observable.just(mockRepos)).when(githubService).publicRepositories(username);

        mainViewModel.onSearchAction(textView, EditorInfo.IME_ACTION_SEARCH, null);
        verify(dataListener).onRepositoriesChanged(mockRepos);
        assertEquals(mainViewModel.infoMessageVisibility.get(), View.INVISIBLE);
        assertEquals(mainViewModel.progressVisibility.get(), View.INVISIBLE);
        assertEquals(mainViewModel.recyclerViewVisibility.get(), View.VISIBLE);
    }

    @Test
    public void shouldSearchInvalidUsername() {
        String username = "invalidUsername";
        TextView textView = new TextView(application);
        textView.setText(username);
        HttpException mockHttpException =
                new HttpException(Response.error(404, mock(ResponseBody.class)));
        when(githubService.publicRepositories(username))
                .thenReturn(Observable.<List<Repository>>error(mockHttpException));

        mainViewModel.onSearchAction(textView, EditorInfo.IME_ACTION_SEARCH, null);
        verify(dataListener, never()).onRepositoriesChanged(anyListOf(Repository.class));
        assertEquals(mainViewModel.infoMessage.get(),
                application.getString(R.string.error_username_not_found));
        assertEquals(mainViewModel.infoMessageVisibility.get(), View.VISIBLE);
        assertEquals(mainViewModel.progressVisibility.get(), View.INVISIBLE);
        assertEquals(mainViewModel.recyclerViewVisibility.get(), View.INVISIBLE);
    }

    @Test
    public void shouldSearchUsernameWithNoRepos() {
        String username = "usernameWithoutRepos";
        TextView textView = new TextView(application);
        textView.setText(username);
        when(githubService.publicRepositories(username))
                .thenReturn(Observable.just(Collections.<Repository>emptyList()));

        mainViewModel.onSearchAction(textView, EditorInfo.IME_ACTION_SEARCH, null);
        verify(dataListener).onRepositoriesChanged(Collections.<Repository>emptyList());
        assertEquals(mainViewModel.infoMessage.get(),
                application.getString(R.string.text_empty_repos));
        assertEquals(mainViewModel.infoMessageVisibility.get(), View.VISIBLE);
        assertEquals(mainViewModel.progressVisibility.get(), View.INVISIBLE);
        assertEquals(mainViewModel.recyclerViewVisibility.get(), View.INVISIBLE);
    }

}