package com.atlassian.stash.internal.notification.pull.activity;

import com.atlassian.bitbucket.i18n.I18nKey;
import com.atlassian.bitbucket.mail.MailMessage;
import com.atlassian.bitbucket.mail.SoyMailBuilder;
import com.atlassian.bitbucket.mail.SoyMailMessageRequest;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.pull.PullRequestActivity;
import com.atlassian.bitbucket.pull.PullRequestActivityVisitor;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.user.TestApplicationUser;
import com.atlassian.bitbucket.watcher.WatchableVisitor;
import com.atlassian.stash.internal.notification.handlers.NotificationMailer;
import com.atlassian.stash.internal.notification.usersettings.BatchEmailFeatureDiscovery;
import com.google.common.collect.ImmutableSet;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Collections;
import java.util.Date;

import static com.atlassian.bitbucket.hamcrest.IsBlankString.notBlank;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class PullRequestActivityRendererTest {

    @Mock
    private BatchEmailFeatureDiscovery featureDiscovery;
    @Mock
    private SoyMailBuilder soyMailBuilder;

    @InjectMocks
    private PullRequestActivityRenderer renderer;

    @Test
    public void testRenderNoActivity() {
        TestApplicationUser user = new TestApplicationUser("foo");
        PullRequest pullRequest = mockPullRequest();
        Iterable<MailMessage> messages = renderer.render(user, pullRequest, Collections.emptySet(),
                Collections.emptySet(), Collections.emptySet(), Collections.emptySet());
        assertThat(messages, is(emptyIterable()));
    }

    @Test
    public void testRender() {
        TestApplicationUser user1 = new TestApplicationUser("foo");
        TestApplicationUser user2 = new TestApplicationUser("bar");
        PullRequest pullRequest = mockPullRequest();
        PullRequestActivity pullRequestActivity = mockPullRequestActivity(pullRequest);
        ToBranchUpdate branchUpdate = new ToBranchUpdate(user2, "to-branch", new Date());

        Iterable<MailMessage> messages = ImmutableSet.of(mock(MailMessage.class));
        when(soyMailBuilder.build(notNull(SoyMailMessageRequest.class))).thenReturn(messages);
        when(pullRequest.accept(notNull(WatchableVisitor.class))).thenReturn("message-id-42");

        assertSame(messages, renderer.render(user1, pullRequest, ImmutableSet.of(pullRequestActivity),
                Collections.emptySet(), ImmutableSet.of(branchUpdate), Collections.emptySet()));

        verify(pullRequestActivity).accept(notNull(PullRequestActivityVisitor.class));
        ArgumentCaptor<SoyMailMessageRequest> requestCaptor = ArgumentCaptor.forClass(SoyMailMessageRequest.class);
        verify(soyMailBuilder).build(requestCaptor.capture());
        SoyMailMessageRequest request = requestCaptor.getValue();
        assertThat(request.getSubjectKey(), notNullValue(I18nKey.class));
        assertThat(request.getRecipients(), contains((ApplicationUser) user1));
        assertThat(request.getCssModuleKey(), equalTo(NotificationMailer.EMAIL_STYLES_MODULE));
        assertThat(request.getSoyTemplateName(), notBlank());
        assertThat(request.getSoyTemplateModuleKey(), equalTo(NotificationMailer.SOY_EMAIL_TEMPLATE_MODULE));
        assertThat(request.getContext(), hasEntry("pullRequest", (Object) pullRequest));
        assertThat(request.getContext(), hasEntry("moduleKey", (Object) NotificationMailer.EMAIL_STYLES_MODULE));
        assertThat(request.getContext(), hasEntry(equalTo("items"), (Matcher) not(emptyIterable())));
    }

    private static PullRequest mockPullRequest() {
        Repository repository = mock(Repository.class, RETURNS_DEEP_STUBS);
        when(repository.getId()).thenReturn(2);
        when(repository.getProject().getKey()).thenReturn("PRJ");

        PullRequest pullRequest = mock(PullRequest.class, RETURNS_DEEP_STUBS);
        when(pullRequest.getId()).thenReturn(42L);
        when(pullRequest.getTitle()).thenReturn("sample pull request");
        when(pullRequest.getFromRef().getRepository()).thenReturn(repository);
        when(pullRequest.getToRef().getRepository()).thenReturn(repository);

        return pullRequest;
    }

    private static PullRequestActivity mockPullRequestActivity(PullRequest pullRequest) {
        PullRequestActivity activity = mock(PullRequestActivity.class);
        when(activity.getPullRequest()).thenReturn(pullRequest);
        return activity;
    }

}