package com.atlassian.bitbucket.mesh.git.batch;

import com.atlassian.bitbucket.mesh.git.builder.GitProcess;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.git.builder.catfile.GitCatFileBatchBuilder;
import com.atlassian.bitbucket.mesh.git.builder.diff.GitDiffTreeBuilder;
import com.atlassian.bitbucket.mesh.git.builder.lstree.GitLsTreeBuilder;
import com.atlassian.bitbucket.mesh.junit.TemporaryDirectory;
import com.atlassian.bitbucket.mesh.layout.StorageLayout;
import com.atlassian.bitbucket.mesh.process.ProcessStdioHandler;
import com.atlassian.bitbucket.mesh.process.ProcessSummary;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcGitTimeouts;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class DefaultBatchManagerMockTest {

    private static final RpcGitTimeouts TIMEOUTS =
            RpcGitTimeouts.newBuilder().setExecution(3600L).setIdle(120L).build();

    @Rule
    public final TemporaryDirectory tempDir = new TemporaryDirectory();
    @Mock
    private BatchChangeCallback batchChangeCallback;
    @InjectMocks
    private DefaultBatchManager batchManager;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private GitProcessBuilderFactory builderFactory;
    @Mock(answer = Answers.RETURNS_SELF)
    private GitCatFileBatchBuilder catFileBatchBuilder;
    @Mock(answer = Answers.RETURNS_SELF)
    private GitDiffTreeBuilder diffTreeBuilder;
    @Mock(answer = Answers.RETURNS_SELF)
    private GitLsTreeBuilder lsTreeBuilder;
    @Mock
    private GitProcess<ProcessSummary> process;
    @Mock
    private Repository repository;
    @Mock
    private StorageLayout storageLayout;

    @SuppressWarnings("unchecked")
    @Before
    public void setUp() {
        when(builderFactory.builder(repository).catFile().batchCheck()).thenReturn(catFileBatchBuilder);
        when(builderFactory.builder(repository).diffTree()).thenReturn(diffTreeBuilder);
        when(builderFactory.builder(repository).lsTree()).thenReturn(lsTreeBuilder);
        when(catFileBatchBuilder.build((ProcessStdioHandler<ProcessSummary>) any())).thenReturn(process);
        when(diffTreeBuilder.build((ProcessStdioHandler<ProcessSummary>) any())).thenReturn(process);
        when(lsTreeBuilder.build((ProcessStdioHandler<ProcessSummary>) any())).thenReturn(process);
        when(process.run()).thenReturn(mock(ProcessSummary.class));
        when(storageLayout.getTempDir()).thenReturn(tempDir.getRoot());
    }

    @Test
    public void testBatchChangesFull() {
        batchManager.changes(new BatchChangesParameters.Builder(repository, TIMEOUTS)
                        .untilCommitId("1")
                        .build(),
                batchChangeCallback);

        InOrder inOrder = inOrder(lsTreeBuilder, process);
        inOrder.verify(lsTreeBuilder).build((any()));
        inOrder.verify(process).run();
        verifyNoInteractions(catFileBatchBuilder, diffTreeBuilder);
    }

    @Test
    public void testBatchChangesIncremental() {
        batchManager.changes(new BatchChangesParameters.Builder(repository, TIMEOUTS)
                        .sinceCommitId("1")
                        .untilCommitId("2")
                        .build(),
                batchChangeCallback);

        InOrder inOrder = inOrder(catFileBatchBuilder, diffTreeBuilder, process);
        inOrder.verify(diffTreeBuilder).build(any());
        inOrder.verify(process).run();
        inOrder.verify(catFileBatchBuilder).build(any());
        inOrder.verify(process).run();
        verifyNoInteractions(lsTreeBuilder);
    }
}
