package com.atlassian.stash.internal.audit.external;

import com.atlassian.plugin.ModuleDescriptor;
import com.atlassian.plugin.Plugin;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.PluginController;
import com.atlassian.plugin.event.events.*;
import com.atlassian.bitbucket.audit.Priority;
import com.atlassian.bitbucket.event.audit.AuditEvent;
import com.atlassian.stash.internal.audit.AbstractAuditEventListenerTest;
import org.junit.Test;
import org.mockito.InjectMocks;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class PluginEventListenerTest extends AbstractAuditEventListenerTest {

    private static final String PLUGIN = "plugin";
    private static final String PLUGIN_CONTAINER = "container";
    private static final String MODULE = "plugin-module";

    @InjectMocks
    private PluginEventListener listener;

    @Test
    public void testOnPluginContainerUnavailable() throws Exception {
        listener.onPluginContainerUnavailable(new PluginContainerUnavailableEvent(PLUGIN_CONTAINER));

        assertStandardPluginData(PLUGIN_CONTAINER, Priority.LOW);
    }

    @Test
    public void testOnPluginDisabled() throws Exception {
        listener.onPluginDisabled(new PluginDisabledEvent(mockPlugin()));

        assertStandardPluginData(PLUGIN, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginEnabled() throws Exception {
        listener.onPluginEnabled(new PluginEnabledEvent(mockPlugin()));

        assertStandardPluginData(PLUGIN, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginFrameworkStarted() throws Exception {
        listener.onPluginFrameworkStarted(new PluginFrameworkStartedEvent(mock(PluginController.class), mock(PluginAccessor.class)));

        assertStandardPluginData("Framework", Priority.LOW);
    }

    @Test
    public void testOnPluginModuleAvailable() throws Exception {
        listener.onPluginModuleAvailable(new PluginModuleAvailableEvent(mockModuleDescriptor()));

        assertStandardPluginData(MODULE, Priority.LOW);
    }

    @Test
    public void testOnPluginModuleDisabled() throws Exception {
        listener.onPluginModuleDisabled(new PluginModuleDisabledEvent(mockModuleDescriptor(), false));

        assertStandardPluginData(MODULE, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginModuleEnabled() throws Exception {
        listener.onPluginModuleEnabled(new PluginModuleEnabledEvent(mockModuleDescriptor()));

        assertStandardPluginData(MODULE, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginModuleUnavailable() throws Exception {
        listener.onPluginModuleUnavailable(new PluginModuleUnavailableEvent(mockModuleDescriptor()));

        assertStandardPluginData(MODULE, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginUninstalled() throws Exception {
        listener.onPluginUninstalled(new PluginUninstalledEvent(mockPlugin()));

        assertStandardPluginData(PLUGIN, Priority.MEDIUM);
    }

    @Test
    public void testOnPluginUpgraded() throws Exception {
        listener.onPluginUpgraded(new PluginUpgradedEvent(mockPlugin()));

        assertStandardPluginData(PLUGIN, Priority.MEDIUM);
    }

    private static ModuleDescriptor mockModuleDescriptor() {
        ModuleDescriptor module = mock(ModuleDescriptor.class);
        when(module.getCompleteKey()).thenReturn(MODULE);
        return module;
    }

    private static Plugin mockPlugin() {
        Plugin plugin = mock(Plugin.class);
        when(plugin.getKey()).thenReturn(PLUGIN);
        return plugin;
    }

    @SuppressWarnings("ConstantConditions")
    private void assertStandardPluginData(String target, Priority priority) {
        AuditEvent event = getAuditEvent();
        assertEquals(USERNAME, event.getEntry().getUser().getName());
        assertTrue(event.getEntry().getTarget().contains(target));
        assertEventCommonDetails(event, priority);
    }
}
