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

import com.atlassian.bitbucket.comment.Comment;
import com.atlassian.bitbucket.mail.MailService;
import com.atlassian.bitbucket.mail.SoyMailBuilder;
import com.atlassian.bitbucket.mail.SoyMailMessageRequest;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.user.DummySecurityService;
import com.atlassian.stash.internal.notification.handlers.NotificationHelper;
import com.atlassian.stash.internal.notification.handlers.NotificationMailer;
import com.atlassian.stash.internal.notification.handlers.NotificationTestUtils;
import com.atlassian.bitbucket.notification.pull.PullRequestCommentNotification;
import com.atlassian.bitbucket.notification.pull.PullRequestNotification;
import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.pull.PullRequestRef;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.stash.internal.notification.usersettings.SendMode;
import com.atlassian.stash.internal.notification.usersettings.UserNotificationSettings;
import com.atlassian.stash.internal.notification.usersettings.UserNotificationSettingsService;
import org.mockito.ArgumentCaptor;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static com.atlassian.stash.internal.notification.pull.PullRequestNotificationUtils.createSubjectKey;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class PullRequestNotificationTestUtils {
    public static PullRequestNotification setupNotification(PullRequestNotification notification) {
        NotificationTestUtils.setupNotification(notification);
        setupPullRequest(notification);
        return notification;
    }

    public static PullRequestCommentNotification setupNotificationComment(PullRequestCommentNotification notification) {
        setupNotification(notification);
        setupComment(notification);
        return notification;
    }

    public static PullRequestNotification setupNotificationPullRequest(PullRequestNotification notification) {
        PullRequestRef pullRequestRef = mock(PullRequestRef.class);
        when(notification.getPullRequest().getToRef()).thenReturn(pullRequestRef);

        Repository repository = mock(Repository.class);
        when(pullRequestRef.getRepository()).thenReturn(repository);

        Project project = mock(Project.class);
        when(repository.getProject()).thenReturn(project);

        return notification;
    }

    private static PullRequest setupPullRequest(PullRequestNotification notification) {
        PullRequest pullRequest = mock(PullRequest.class);
        when(notification.getPullRequest()).thenReturn(pullRequest);
        return pullRequest;
    }

    private static Comment setupComment(PullRequestCommentNotification notification) {
        Comment comment = mock(Comment.class);
        when(notification.getComment()).thenReturn(comment);
        return comment;
    }

    public static void assertNotification(PullRequestNotification notification, Map<String, Object> context) {
        NotificationTestUtils.assertNotification(notification, context);
        assertEquals("Check pull request", notification.getPullRequest(), context.get("pullRequest"));
    }

    public static void assertNotificationComment(PullRequestCommentNotification notification, Map<String, Object> context) {
        assertNotification(notification, context);
        assertEquals("Check comment", notification.getComment(), context.get("comment"));
    }

    public static void assertMailHandler(Function<NotificationHelper,
            AbstractPullRequestNotificationHandler<? extends PullRequestNotification>> notificationHandlerBuilder,
                                         PullRequestNotification notification, String template) {

        MailService mailService = mock(MailService.class);
        when(mailService.isHostConfigured()).thenReturn(true);

        //SoyMailBuilderImpl tested elsewhere
        SoyMailBuilder mailBuilder = mock(SoyMailBuilder.class);
        when(mailBuilder.build(any())).thenReturn(Collections.emptySet());

        NotificationMailer mailer = new NotificationMailer(mailService, mailBuilder);

        UserNotificationSettingsService notificationSettingsService = mock(UserNotificationSettingsService.class);
        ApplicationUser recipient = mock(ApplicationUser.class);
        UserNotificationSettings userNotificationSettings = mock(UserNotificationSettings.class);
        when(userNotificationSettings.getSendMode()).thenReturn(SendMode.IMMEDIATE);
        when(notificationSettingsService.getSettingsForUser(recipient)).thenReturn(userNotificationSettings);

        AbstractPullRequestNotificationHandler notificationHandler = notificationHandlerBuilder
                .apply(new NotificationHelper(mailer, new DummySecurityService(), notificationSettingsService));

        setupNotification(notification);

        PullRequestRef ref = mock(PullRequestRef.class);
        Repository repository = mock(Repository.class);
        Project project = mock(Project.class);
        when(repository.getProject()).thenReturn(project);
        when(ref.getRepository()).thenReturn(repository);
        when(notification.getPullRequest().getToRef()).thenReturn(ref);

        notificationHandler.handle(notification, singletonList(recipient));

        ArgumentCaptor<SoyMailMessageRequest> messageCaptor = ArgumentCaptor.forClass(SoyMailMessageRequest.class);
        verify(mailBuilder).build(messageCaptor.capture());

        List<SoyMailMessageRequest> messages = messageCaptor.getAllValues();
        assertEquals(1, messages.size());
        SoyMailMessageRequest message = messages.get(0);

        assertEquals(NotificationMailer.EMAIL_STYLES_MODULE, message.getCssModuleKey());
        assertEquals(notificationHandler.getContext(notification), message.getContext());
        assertEquals(singletonList(recipient), message.getRecipients());
        assertEquals(NotificationMailer.SOY_EMAIL_TEMPLATE_MODULE, message.getSoyTemplateModuleKey());
        assertEquals(template, message.getSoyTemplateName());
        assertEquals(createSubjectKey(notification.getPullRequest()).getKey(), message.getSubjectKey().getKey());

    }
}
