package com.atlassian.stash.internal.notification;

import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.PluginController;
import com.atlassian.stash.internal.plugin.NotificationHandlerModuleDescriptor;
import com.atlassian.bitbucket.notification.NotificationHandler;
import com.atlassian.bitbucket.notification.pull.CommentAddedPullRequestNotification;
import com.atlassian.bitbucket.notification.pull.PullRequestClosedNotification;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.google.common.collect.Lists;
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.ArrayList;

import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class DefaultNotificationManagerTest {

    @Mock
    private NotificationHandlerModuleDescriptor descriptor;
    @Mock
    private NotificationAddresser notificationAddresser;
    @Mock
    private NotificationHandler notificationHandler;
    @Mock
    private PluginAccessor pluginAccessor;
    @Mock
    private PluginController pluginController;
    @Mock
    private ApplicationUser user;

    @InjectMocks
    private DefaultNotificationManager notificationManager;

    @Before
    public void setUp() {
        when(descriptor.getModule()).thenReturn(notificationHandler);
    }

    @Test
    public void testGlobalCommentHappyPath() {
        CommentAddedPullRequestNotification notification = mock(CommentAddedPullRequestNotification.class);

        when(descriptor.getNotificationClass()).thenReturn(notification.getClass().getCanonicalName());
        when(pluginAccessor.getEnabledModuleDescriptorsByClass(NotificationHandlerModuleDescriptor.class)).thenReturn(Lists.newArrayList(descriptor));

        ArrayList<ApplicationUser> recipients = Lists.newArrayList(user);
        when(notificationAddresser.getRecipients(notification)).thenReturn(recipients);

        notificationManager.dispatch(notification);

        verify(notificationHandler).handle(eq(notification), anyList());
    }

    @Test
    public void testInitiatorNotNotified() {
        CommentAddedPullRequestNotification notification = mock(CommentAddedPullRequestNotification.class);

        when(descriptor.getNotificationClass()).thenReturn(notification.getClass().getCanonicalName());
        when(pluginAccessor.getEnabledModuleDescriptorsByClass(NotificationHandlerModuleDescriptor.class)).thenReturn(Lists.newArrayList(descriptor));

        ApplicationUser initiator = mock(ApplicationUser.class);

        ArrayList<ApplicationUser> stashUsers = Lists.newArrayList(initiator, user);
        when(notificationAddresser.getRecipients(notification)).thenReturn(stashUsers);
        when(notification.getUser()).thenReturn(initiator);

        notificationManager.dispatch(notification);

        verify(notificationHandler).handle(eq(notification), argThat(not(hasItem(initiator))));
    }

    @Test
    public void testMismatchedPluginClass() {
        PullRequestClosedNotification notification = mock(PullRequestClosedNotification.class);
        NotificationHandler<CommentAddedPullRequestNotification> commentHandler = new NotificationHandler<CommentAddedPullRequestNotification>() {
            @Override
            public void handle(CommentAddedPullRequestNotification notification, Iterable<ApplicationUser> recipients) {
            }
        };

        when(descriptor.getModule()).thenReturn(commentHandler);

        when(descriptor.getNotificationClass()).thenReturn(notification.getClass().getCanonicalName());

        final String notificationHandlerKey = "com.bad.plugin:bad-plugin-module";
        when(descriptor.getCompleteKey()).thenReturn(notificationHandlerKey);

        when(pluginAccessor.getEnabledModuleDescriptorsByClass(NotificationHandlerModuleDescriptor.class)).thenReturn(Lists.newArrayList(descriptor));

        ArrayList<ApplicationUser> stashUsers = Lists.newArrayList(user);
        when(notificationAddresser.getRecipients(notification)).thenReturn(stashUsers);

        notificationManager.dispatch(notification);

        verify(pluginController).disablePluginModule(notificationHandlerKey);
    }
}
