package com.atlassian.stash.internal.pull;

import com.atlassian.plugin.ModuleDescriptor;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.stash.internal.plugin.PullRequestPropertyProviderDescriptor;
import com.atlassian.bitbucket.property.PropertyMap;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.pull.PullRequestPropertyContext;
import com.atlassian.bitbucket.pull.PullRequestPropertyProvider;
import com.atlassian.bitbucket.util.Page;
import com.google.common.collect.ImmutableList;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import javax.annotation.Nonnull;
import java.util.List;

import static com.atlassian.bitbucket.util.PageUtils.createPage;
import static com.atlassian.bitbucket.util.PageUtils.newRequest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class PluginPullRequestEnricherTest {

    @Mock
    private PluginAccessor pluginAccessor;
    @Spy
    private PullRequestPropertyProvider pluginPropertyProvider = new PullRequestPropertyProvider() {
        @Override
        public void provideProperties(@Nonnull PullRequestPropertyContext context) {
            for (PullRequest pullRequest : context) {
                context.setProperty(pullRequest, "pull-request-id", pullRequest.getId());
            }
        }
    };

    @Mock
    private ModuleDescriptor<PullRequestPropertyProvider> propertyProviderDescriptor;

    @InjectMocks
    private PluginPullRequestEnricher enricher;

    @Before
    @SuppressWarnings("unchecked")
    public void setUpPluginModules() {
        when(pluginAccessor.getEnabledModuleDescriptorsByClass(PullRequestPropertyProviderDescriptor.class))
                .thenReturn((List) ImmutableList.of(propertyProviderDescriptor));

        when(propertyProviderDescriptor.getModule()).thenReturn(pluginPropertyProvider);
    }

    @Test
    public void testEnrichIterable() {
        InternalPullRequest pullRequest1 = newPullRequest(1L);
        InternalPullRequest pullRequest2 = newPullRequest(2L);
        Iterable<InternalPullRequest> iterable = ImmutableList.of(pullRequest1, pullRequest2);

        Iterable<InternalPullRequest> result = enricher.enrich(iterable);

        assertEquals(ImmutableList.copyOf(iterable), ImmutableList.copyOf(result));
        assertPropertiesProvided(pullRequest1);
        assertPropertiesProvided(pullRequest2);
    }

    @Test
    public void testEnrichPage() {
        InternalPullRequest pullRequest1 = newPullRequest(1L);
        InternalPullRequest pullRequest2 = newPullRequest(2L);
        Page<InternalPullRequest> page = createPage(ImmutableList.of(pullRequest1, pullRequest2), newRequest(0, 5));

        Page<InternalPullRequest> result = enricher.enrich(page);

        assertEquals(ImmutableList.copyOf(page.getValues()), ImmutableList.copyOf(result.getValues()));
        assertPropertiesProvided(pullRequest1);
        assertPropertiesProvided(pullRequest2);
    }

    private void assertPropertiesProvided(InternalPullRequest pullRequest) {
        assertThat(pullRequest.getProperties().keySet(), Matchers.<String>hasSize(1));
        assertThat(pullRequest.getProperties(), Matchers.<String, Object>hasEntry("pull-request-id", pullRequest.getId()));
    }

    private static InternalPullRequest newPullRequest(long id) {
        InternalPullRequest pullRequest = spy(new InternalPullRequest());
        when(pullRequest.getId()).thenReturn(id);

        return pullRequest;
    }

    private static InternalPullRequest newPullRequestWithProperty(long id, String key, Object value) {
        InternalPullRequest pullRequest = newPullRequest(id);
        pullRequest.setProperties(new PropertyMap.Builder().property(key, value).build());

        return pullRequest;
    }
}