package com.atlassian.bitbucket.mesh.git;

import com.atlassian.bitbucket.mesh.config.HostingConfig;
import com.atlassian.bitbucket.mesh.event.EventPublisher;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilder;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.git.builder.uploadpack.GitUploadPackBuilder;
import com.atlassian.bitbucket.mesh.git.cache.PackCacheService;
import com.atlassian.bitbucket.mesh.git.hook.GitHookService;
import com.atlassian.bitbucket.mesh.git.hook.HookRequestHandle;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.repository.RepositoryManager;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcHostingWriteStreamFragment;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcUploadPackFragment;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcUploadPackRequest;
import com.google.protobuf.MessageOrBuilder;
import io.grpc.stub.StreamObserver;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static com.atlassian.bitbucket.mesh.rpc.v1.RpcHostingOperationType.HOSTING_OP_REF_ADVERTISEMENT;
import static com.atlassian.bitbucket.mesh.rpc.v1.RpcHostingOperationType.HOSTING_OP_UNSPECIFIED;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class UploadPackFragmentHandlerTest {

    @Mock
    private GitProcessBuilderFactory builderFactory;
    @Mock
    private EventPublisher eventPublisher;
    @Mock
    private GitHookService gitHookService;
    private UploadPackFragmentHandler handler;
    @Mock
    private HookRequestHandle hookHandle;
    @Mock
    private HostingConfig hostingConfig;
    @Mock
    private StreamObserver<RpcHostingWriteStreamFragment> observer;
    @Mock
    private PackCacheService packCacheService;
    @Mock
    private GitProcessBuilder processBuilder;
    @Mock
    private GitQuarantineRegistry quarantineRegistry;
    @Mock
    private Repository repository;
    @Mock
    private RepositoryManager repositoryManager;
    @Mock
    private GitUploadPackBuilder uploadPackBuilder;

    @Before
    public void setUp() {
        when(builderFactory.builder(any(MessageOrBuilder.class))).thenReturn(processBuilder);
        when(gitHookService.registerRequest(any(Repository.class), any())).thenReturn(hookHandle);
        when(hookHandle.configure(any(GitUploadPackBuilder.class))).thenReturn(uploadPackBuilder);
        when(hostingConfig.isFilterAllowed()).thenReturn(true);
        when(processBuilder.uploadPack()).thenReturn(uploadPackBuilder);
        when(repositoryManager.getById(anyString())).thenReturn(repository);

        when(uploadPackBuilder.advertiseRefs(anyBoolean())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.statelessRpc(anyBoolean())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.strict(anyBoolean())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.throttled(any())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.timeout(any())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.withConfiguration(anyString(), anyBoolean())).thenReturn(uploadPackBuilder);
        when(uploadPackBuilder.withEnvironment(anyString(), anyString())).thenReturn(uploadPackBuilder);

        handler = new UploadPackFragmentHandler(builderFactory, gitHookService,
                hostingConfig, packCacheService, repositoryManager);
    }

    @Test
    public void testOperationTypeWhenCachingDisabled() {
        handler.createBuilder(RpcUploadPackFragment.newBuilder()
                .setRequest(RpcUploadPackRequest.newBuilder()
                        .setRepository("The Test Repository")
                        .build())
                .build());

        assertThat(handler.getOperationType(), equalTo(HOSTING_OP_UNSPECIFIED));
    }

    @Test
    public void testOperationTypeWhenCachingEnabled() {
        when(packCacheService.isEnabledForSsh()).thenReturn(true);

        handler = new UploadPackFragmentHandler(builderFactory, gitHookService,
                hostingConfig, packCacheService, repositoryManager);
        handler.createBuilder(RpcUploadPackFragment.newBuilder()
                .setRequest(RpcUploadPackRequest.newBuilder()
                        .setRepository("The Test Repository")
                        .build())
                .build());

        assertThat(handler.getOperationType(), equalTo(HOSTING_OP_REF_ADVERTISEMENT));
    }
}