package com.atlassian.bitbucket.internal.scm.git.lfs.ssh;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.internal.scm.git.lfs.BadBatchRequestException;
import com.atlassian.bitbucket.internal.scm.git.lfs.settings.GitLfsSettingsService;
import com.atlassian.bitbucket.internal.scm.git.lfs.jwt.GitLfsJwtHelper;
import com.atlassian.bitbucket.nav.NavBuilder;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.RepositoryService;
import com.atlassian.bitbucket.scm.ssh.ExitCodeCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.InputStream;
import java.io.OutputStream;

import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class GitLfsSshScmRequestHandlerTest {

    @Mock
    private I18nService i18nService;
    @InjectMocks
    private GitLfsSshScmRequestHandler instance;
    @Mock
    private GitLfsJwtHelper jwtHelper;
    @Mock
    private NavBuilder navBuilder;
    @Mock
    private Repository repository;
    @Mock
    private RepositoryService repositoryService;
    @Mock
    private GitLfsSettingsService settingsService;

    @Before
    public void setup() {
        when(repositoryService.getBySlug(anyString(), anyString(), anyString())).thenReturn(repository);
        when(settingsService.isEnabled()).thenReturn(true);
        when(settingsService.isEnabled(any(Repository.class))).thenReturn(true);
    }

    @Test
    public void testCreate() throws Exception {
        createTestHelper("git-lfs-authenticate project_1/rep_1.git download", true);
        createTestHelper("git-lfs-authenticate project_1/rep_1.git upload", true);

        // Some unusual names - Valid repository names must start with a letter or number
        // and may contain spaces, hyphens, underscores and periods. However spaces are
        // converted to hyphens when generating the slug.
        createTestHelper("git-lfs-authenticate project_1/1_rep.git download", true);
        createTestHelper("git-lfs-authenticate project_1/foo.bar.git download", true);
        createTestHelper("git-lfs-authenticate project_1/foo-bar.git download", true);
        createTestHelper("git-lfs-authenticate project_1/1.git download", true);
        createTestHelper("git-lfs-authenticate project_1/1.2..a.b.c.git download", true);
    }

    @Test
    public void testCreateWithNamespace() throws Exception {
        createTestHelper("git-lfs-authenticate primary/project_1/rep_1.git download", true);
        createTestHelper("git-lfs-authenticate primary/project_1/rep_1.git upload", true);

        createTestHelper("git-lfs-authenticate primary/project_1/1_rep.git download", true);
        createTestHelper("git-lfs-authenticate primary/project_1/foo.bar.git download", true);
        createTestHelper("git-lfs-authenticate primary/project_1/foo-bar.git download", true);
        createTestHelper("git-lfs-authenticate primary/project_1/1.git download", true);
        createTestHelper("git-lfs-authenticate primary/project_1/1.2..a.b.c.git download", true);
    }

    @Test
    public void testCreateWithOid() throws Exception {
        // The legacy API used to send the OID, we can still accept it
        createTestHelper("git-lfs-authenticate project_1/rep_1.git download " +
                "234214ed45b33470cbe66505e116b19d3eb46787cf3cc4f7e8f13ee107ff897", true);
        createTestHelper("git-lfs-authenticate project_1/rep_1.git upload " +
                "234214ed45b33470cbe66505e116b19d3eb46787cf3cc4f7e8f13ee107ff897", true);
    }

    @Test(expected = BadBatchRequestException.class)
    public void testCreateWithInvalidOperation() throws Exception {
        createTestHelper("git-lfs-authenticate project_1/rep_1.git invalidoperation", false);
    }

    @Test
    public void testCreateNotLfsCommand() throws Exception {
        createTestHelper("git project_1/rep_1.git download", false);
        createTestHelper("", false);
    }

    @Test
    public void testCreateWhileLfsGloballyDisabled() throws Exception {
        // Setup
        when(settingsService.isEnabled()).thenReturn(false);

        // Execute & verify
        createTestHelper("git-lfs-authenticate project_1/rep_1.git download", false);
    }

    /**
     * See issue BSERVDEV-11539 for an explanation as to why we don't return an error
     * from the SSH handler in the case LFS is disabled
     */
    @Test
    public void testCreateWhileLfsDisabledOnRepo() throws Exception {
        // Setup
        when(settingsService.isEnabled(any(Repository.class))).thenReturn(false);

        // Execute & verify
        createTestHelper("git-lfs-authenticate project_1/rep_1.git download", true);
    }

    @Test
    public void testSupports() throws Exception {
        assertTrue(instance.supports("git-lfs-authenticate"));
        assertFalse(instance.supports("git"));
        assertFalse(instance.supports(""));
    }

    private void createTestHelper(String command, boolean expectToHandle) {
        InputStream in = mock(InputStream.class);
        OutputStream out = mock(OutputStream.class);
        OutputStream err = mock(OutputStream.class);
        ExitCodeCallback exitCodeCallback = mock(ExitCodeCallback.class);

        assertEquals(command, expectToHandle, instance.create(command, in, out, err, exitCodeCallback).isPresent());
    }
}