package com.atlassian.bitbucket.internal.mirroring.mirror.scm.check;

import com.atlassian.bitbucket.i18n.SimpleI18nService;
import com.atlassian.bitbucket.mirroring.mirror.MirroredRepositoryService;
import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.ScmRequest;
import com.atlassian.bitbucket.scm.ScmRequestCheck;
import com.atlassian.bitbucket.server.ApplicationMode;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import static com.atlassian.bitbucket.mirroring.mirror.MirroredRepositoryStatus.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class MirrorredRepositoryNotAvailableCheckTest {

    private ScmRequestCheck check;
    @Spy
    private SimpleI18nService i18nService;
    @Mock
    private MirroredRepositoryService mirroredRepositoryService;
    @Mock
    private Project project;
    @Mock
    private Repository repository;
    @Mock
    private ScmRequest scmRequest;

    @Before
    public void setUp() throws Exception {
        when(scmRequest.getRepository()).thenReturn(repository);

        when(repository.getProject()).thenReturn(project);

        when(mirroredRepositoryService.getStatus(repository)).thenReturn(AVAILABLE);
    }

    @Test
    public void testDefaultMode() throws Exception {
        check = newCheck(ApplicationMode.DEFAULT);

        assertTrue(check.check(scmRequest));
        verifyNoMoreInteractions(i18nService);
        verify(scmRequest, never()).sendError(anyString(), anyString());
    }

    @Test
    public void testInitialisedRepositoryInMirrorMode() throws Exception {
        check = newCheck();

        assertTrue(check.check(scmRequest));
        verify(scmRequest, never()).sendError(anyString(), anyString());
    }

    @Test
    public void testUninitialisedRepositoryInMirrorMode() throws Exception {
        when(mirroredRepositoryService.getStatus(repository)).thenReturn(INITIALIZING);

        check = newCheck();

        assertFalse(check.check(scmRequest));
        verify(scmRequest).sendError(anyString(), anyString());
    }

    @Test
    public void testRepositoryNotMirroredInMirrorMode() throws Exception {
        when(mirroredRepositoryService.getStatus(repository)).thenReturn(NOT_MIRRORED);

        check = newCheck();

        assertFalse(check.check(scmRequest));
        verify(scmRequest).sendError(anyString(), anyString());
    }

    @Test
    public void testRepositoryUnitialisedAndInErrorInMirrorMode() throws Exception {
        when(mirroredRepositoryService.getStatus(repository)).thenReturn(ERROR_INITIALIZING);

        check = newCheck();

        assertFalse(check.check(scmRequest));
        verify(scmRequest).sendError(anyString(), anyString());
    }

    @Test
    public void testRepositoryInitialisedAndInErrorInMirrorMode() throws Exception {
        when(mirroredRepositoryService.getStatus(repository)).thenReturn(ERROR_AVAILABLE);

        check = newCheck();

        assertTrue(check.check(scmRequest));
        verify(scmRequest, never()).sendError(anyString(), anyString());
    }

    private MirrorredRepositoryNotAvailableCheck newCheck() {
        return newCheck(ApplicationMode.MIRROR);
    }

    private MirrorredRepositoryNotAvailableCheck newCheck(ApplicationMode mode) {
        return new MirrorredRepositoryNotAvailableCheck(i18nService, mirroredRepositoryService, () -> mode);
    }
}