package com.atlassian.stash.internal.scm.git.pull;

import com.atlassian.bitbucket.scm.git.GitAgent;
import com.atlassian.bitbucket.util.FileUtils;
import com.google.common.io.Files;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.io.IOException;

import static org.mockito.Mockito.*;

public class ExistingPullRequestAutoMergeStrategyTest extends AbstractPullRequestGitTest {

    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Mock
    private GitAgent agent;
    @Mock
    private PullRequestRefs refs;
    @Mock
    private PullRequestAutoMergeRequest request;
    @InjectMocks
    private ExistingPullRequestAutoMergeStrategy strategy;

    public ExistingPullRequestAutoMergeStrategyTest() {
        super(5L);
    }

    @Override
    public void setup() {
        super.setup();

        prepareRefs("branch_that_has_same_text_file_modified_on_both_clean_merge_src",
                "306d584aa574fa74901d3e288b2931b2c4f0e927",
                "branch_that_has_same_text_file_modified_on_both_clean_merge_trgt",
                "7fa77c6e34c6c53de0bb880fc2b0b7924a601cd2");

        request = new PullRequestAutoMergeRequest.Builder(pullRequest)
                .author(author)
                .repositoryDir(folder.getRoot())
                .build();
    }

    @Test
    public void testMerge() throws IOException {
        String mergeRef = markMergeType(PullRequestMergeType.CLEAN);

        doReturn(mockBranch("merge")).when(agent).resolveBranch(same(repository), eq(mergeRef), eq(true));
        doReturn(mockBranch("306d584aa574fa74901d3e288b2931b2c4f0e927")).when(refs).resolveFrom();
        doReturn(mockBranch("7fa77c6e34c6c53de0bb880fc2b0b7924a601cd2")).when(refs).resolveTo();

        PullRequestMerge merge = strategy.merge(request, refs);
        assertNotNull(merge);
        assertEquals("merge", merge.getHash());
        assertSame(PullRequestMergeType.CLEAN, merge.getType());

        verify(agent).resolveBranch(same(repository), eq(mergeRef), eq(true));
        verify(refs).resolveFrom();
        verify(refs).resolveTo();
    }

    @Test
    public void testMergeMissingFrom() {
        assertNull(strategy.merge(request, refs));

        verify(refs).resolveFrom();
        verifyNoMoreInteractions(refs);
        verifyZeroInteractions(agent);
    }

    @Test
    public void testMergeMissingMergeType() {
        doReturn(mockBranch("306d584aa574fa74901d3e288b2931b2c4f0e927")).when(refs).resolveFrom();
        doReturn(mockBranch("7fa77c6e34c6c53de0bb880fc2b0b7924a601cd2")).when(refs).resolveTo();

        assertNull(strategy.merge(request, refs));

        verify(refs).resolveFrom();
        verify(refs).resolveTo();
        verifyZeroInteractions(agent);
    }

    @Test
    public void testMergeMissingMerge() throws IOException {
        //Simulate the (impossible, but...) case where the merge type marker exists but the merge itself cannot
        //be resolved. This works by not training a return for the merge on the agent
        String mergeRef = markMergeType(PullRequestMergeType.BASE);

        doReturn(mockBranch("306d584aa574fa74901d3e288b2931b2c4f0e927")).when(refs).resolveFrom();
        doReturn(mockBranch("7fa77c6e34c6c53de0bb880fc2b0b7924a601cd2")).when(refs).resolveTo();

        assertNull(strategy.merge(request, refs));

        verify(agent).resolveBranch(same(repository), eq(mergeRef), eq(true));
        verify(refs).resolveFrom();
        verify(refs).resolveTo();
    }

    @Test
    public void testMergeMissingTo() {
        doReturn(mockBranch("306d584aa574fa74901d3e288b2931b2c4f0e927")).when(refs).resolveFrom();

        assertNull(strategy.merge(request, refs));

        verify(refs).resolveFrom();
        verify(refs).resolveTo();
        verifyNoMoreInteractions(refs);
        verifyZeroInteractions(agent);
    }

    private String markMergeType(PullRequestMergeType mergeType) throws IOException {
        //Simulate the existence of a merge-clean merge (with invalid contents, no less, to verify it's not resolved)
        PullRequestRefBuilder builder = PullRequestRefBuilder.darkRef()
                .id(pullRequest);
        FileUtils.mkdir(builder.toFile(folder.getRoot()));
        Files.touch(builder.name(mergeType.getRefName()).toFile(folder.getRoot()));

        return builder.type(PullRequestRefType.MERGE).toRef();
    }
}
