package com.atlassian.stash.internal.build.branch;

import com.atlassian.bitbucket.build.BuildState;
import com.atlassian.bitbucket.build.BuildSummary;
import com.atlassian.bitbucket.build.BuildStatusService;
import com.atlassian.bitbucket.AuthorisationException;
import com.atlassian.stash.internal.build.SimpleBuildSummary;
import com.atlassian.stash.internal.build.rest.RestBuildStats;
import com.atlassian.bitbucket.repository.Ref;
import com.atlassian.bitbucket.repository.RefMetadataContext;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.List;
import java.util.Map;
import java.util.Set;

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

@RunWith(MockitoJUnitRunner.class)
public class BuildStatusRefMetadataProviderTest {

    @Mock
    BuildStatusService service;

    @Mock
    RefMetadataContext context;

    @InjectMocks
    BuildStatusRefMetadataProvider provider;

    @Test
    public void testGetMetadata() throws Exception {
        setupMockRefs("abcde", "defgh", "lmpqr");
        setupMockBuildStatus("abcde", "defgh", "lmpqr");
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(3, results.size());
    }

    @Test
    public void testGetMetadataDuplicateCommitIds() throws Exception {
        setupMockRefs("abcde", "abcde", "abcde");
        setupMockBuildStatus("abcde");
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(3, results.size());
    }


    @Test
    public void testGetMetadataCommitIdsMissingFromBuildStatus() throws Exception {
        setupMockRefs("abcde", "defgh", "lmpqr");
        setupMockBuildStatus("abcde");
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(1, results.size());
    }

    @Test
    public void testGetMetadataNoInputs() throws Exception {
        setupMockRefs();
        setupMockBuildStatus();
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(0, results.size());
    }

    @Test
    public void testGetMetadataNoResults() throws Exception {
        setupMockRefs("abcde");
        setupMockBuildStatus();
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(0, results.size());
    }

    @Test
    public void testGetMetadataAuthorizationException() throws Exception {
        setupMockRefs("abcde");
        when(service.getSummaries(any(List.class))).thenThrow(mock(AuthorisationException.class));
        Map<Ref, RestBuildStats> results = provider.getMetadata(context);
        assertEquals(0, results.size());
    }

    void setupMockRefs(String... commitHashes) {
        Set<Ref> refs = Sets.newHashSetWithExpectedSize(commitHashes.length);
        for (String commitHash : commitHashes) {
            Ref ref = mock(Ref.class);
            when(ref.getLatestCommit()).thenReturn(commitHash);
            refs.add(ref);
        }
        when(context.getRefs()).thenReturn(refs);
    }

    void setupMockBuildStatus(String... latestCommits) {
        Map<String, BuildSummary> results = Maps.newHashMapWithExpectedSize(latestCommits.length);
        for (String latestCommit : latestCommits) {
            results.put(latestCommit, new SimpleBuildSummary(Maps.<BuildState, Integer>newHashMap()));
        }
        when(service.getSummaries(any(List.class))).thenReturn(results);
    }
}
