package com.atlassian.stash.internal.web.pull;

import com.atlassian.bitbucket.pull.*;
import com.atlassian.bitbucket.repository.Ref;
import com.atlassian.bitbucket.repository.RefMetadataContext;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.bitbucket.permission.PermissionService;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
import com.atlassian.bitbucket.util.PageUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
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.util.Map;
import java.util.Set;

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

@RunWith(MockitoJUnitRunner.class)
public class PullRequestMetadataProviderTest {

    @Mock
    PermissionService permissionService;

    @Mock
    PullRequestService pullRequestService;

    @InjectMocks
    PullRequestMetadataProvider pullRequestMetadataProvider;

    @Before
    public void setup() {
        when(permissionService.hasGlobalPermission(Permission.LICENSED_USER)).thenReturn(Boolean.TRUE);
    }

    @Test
    public void testGetMetadataEmpty() throws Exception {
        testProviderBasics(PageUtils.<PullRequest>createEmptyPage(PageUtils.newRequest(0, 25)), Sets.<Ref>newHashSet(), 0);
    }

    @Test
    public void testGetMetadataAnon() throws Exception {
        when(permissionService.hasGlobalPermission(Permission.LICENSED_USER)).thenReturn(Boolean.FALSE);
        PullRequest pr1 = mock(PullRequest.class);
        when(pr1.getState()).thenReturn(PullRequestState.OPEN);
        PullRequestRef ref1 = mock(PullRequestRef.class);
        when(pr1.getFromRef()).thenReturn(ref1);

        testProviderBasics(PageUtils.<PullRequest>createPage(Lists.newArrayList(pr1), PageUtils.newRequest(0, 25)), Sets.<Ref>newHashSet(ref1), 0);
    }

    @Test
    public void testGetMetadataSingle() throws Exception {
        PullRequest pr1 = mock(PullRequest.class);
        when(pr1.getState()).thenReturn(PullRequestState.OPEN);
        PullRequestRef ref1 = mock(PullRequestRef.class);
        when(pr1.getFromRef()).thenReturn(ref1);
        when(ref1.getId()).thenReturn("1");

        Map<Ref, Map<String, Object>> result = testProviderBasics(PageUtils.<PullRequest>createPage(Lists.newArrayList(pr1), PageUtils.newRequest(0, 25)), Sets.<Ref>newHashSet(ref1), 1);
        assertFalse(result.get(ref1).containsKey("open"));
        assertEquals(pr1, result.get(ref1).get("pullRequest"));
    }

    @Test
    public void testGetMetadataMultiple() throws Exception {
        PullRequest pr1 = mock(PullRequest.class);

        when(pr1.getState()).thenReturn(PullRequestState.OPEN);
        PullRequest pr2 = mock(PullRequest.class);
        when(pr2.getState()).thenReturn(PullRequestState.DECLINED);
        PullRequestRef ref1 = mock(PullRequestRef.class);
        when(ref1.getId()).thenReturn("1");
        when(pr1.getFromRef()).thenReturn(ref1);
        when(pr2.getFromRef()).thenReturn(ref1);

        Map<Ref, Map<String, Object>> result = testProviderBasics(PageUtils.<PullRequest>createPage(Lists.newArrayList(pr1, pr2), PageUtils.newRequest(0, 25)), Sets.<Ref>newHashSet(ref1), 1);
        assertEquals(1, result.get(ref1).get("open"));
        assertEquals(1, result.get(ref1).get("declined"));
    }

    private Map<Ref, Map<String, Object>> testProviderBasics(Page<PullRequest> pullRequests, Set<Ref> refs,
                                                             int expected) {
        when(pullRequestService.search(any(PullRequestSearchRequest.class), any(PageRequest.class))).thenReturn(pullRequests);
        RefMetadataContext context = mock(RefMetadataContext.class);
        when(context.getRefs()).thenReturn(refs);
        Repository repository = mock(Repository.class);
        when(context.getRepository()).thenReturn(repository);
        Map<Ref, Map<String, Object>> result = pullRequestMetadataProvider.getMetadata(context);
        assertEquals(expected, result.size());
        return result;
    }


}
