package com.atlassian.stash.internal.audit;

import com.atlassian.bitbucket.audit.AuditEntry;
import com.atlassian.bitbucket.audit.Priority;
import com.atlassian.bitbucket.event.audit.AuditEvent;
import com.atlassian.bitbucket.event.license.LicenseChangedEvent;
import com.atlassian.bitbucket.event.server.*;
import com.atlassian.bitbucket.event.throttle.TicketRejectedEvent;
import com.atlassian.bitbucket.mail.MailHostConfiguration;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.junit.Test;
import org.mockito.InjectMocks;

import static com.atlassian.bitbucket.mail.MailProtocol.SMTP;
import static org.junit.Assert.*;

public class ServerEventListenerTest extends AbstractAuditEventListenerTest {

    @InjectMocks
    private ServerEventListener listener;

    @Test
    public void testOnApplicationConfigurationChanged() throws Exception {
        listener.onApplicationConfigurationChanged(new DisplayNameChangedEvent(this, "old", "n\"ew"));

        AuditEvent event = getAuditEvent();
        AuditEntry auditEntry = event.getEntry();
        assertContains(auditEntry.getDetails(), "n\\\"ew", "old");
        assertEquals(ApplicationConfigurationChangedEvent.Property.DISPLAY_NAME.toString(), auditEntry.getTarget());
        assertEquals(DisplayNameChangedEvent.class.getSimpleName(), auditEntry.getAction());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnApplicationConfigurationChangedNulls() throws Exception {
        listener.onApplicationConfigurationChanged(new DisplayNameChangedEvent(this, null, null));

        AuditEvent event = getAuditEvent();
        AuditEntry auditEntry = event.getEntry();
        assertContains(auditEntry.getDetails(), "null");
        assertEquals(ApplicationConfigurationChangedEvent.Property.DISPLAY_NAME.toString(), auditEntry.getTarget());
        assertEquals(DisplayNameChangedEvent.class.getSimpleName(), auditEntry.getAction());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnApplicationSetup() throws Exception {
        listener.onApplicationConfigurationChanged(new ApplicationSetupEvent(this, false, true));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();

        assertEquals(ApplicationSetupEvent.class.getSimpleName(), entry.getAction());
        assertEquals(ApplicationConfigurationChangedEvent.Property.SERVER_IS_SETUP.toString(), entry.getTarget());

        assertConfigurationChangedDetails("false", "true", entry.getDetails());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnLicenseChanged() throws Exception {
        listener.onLicenseChanged(new LicenseChangedEvent(this));

        AuditEvent event = getAuditEvent();
        assertEquals(LicenseChangedEvent.class.getSimpleName(), event.getEntry().getAction());
        assertNotNull(event.getEntry().getTimestamp());
        assertNull(event.getEntry().getDetails());
        assertEquals("System", event.getEntry().getTarget());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnMailHostConfigurationChanged() throws Exception {
        listener.onMailHostConfigurationChanged(new MailHostConfigurationChangedEvent(this,
                new MailHostConfiguration.Builder().hostname("hostname").port(7990).username("user").password("secret").protocol(SMTP).useStartTls(true).build(),
                new MailHostConfiguration.Builder().hostname("hostname2").port(7811).username("user2").password("secret2").protocol(SMTP).useStartTls(true).build()));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), "hostname", "hostname2", "7990", "7811", "user", "user2");
        assertNotContains(entry.getDetails(), "secret", "secret2");
        assertEquals(ApplicationConfigurationChangedEvent.Property.MAIL_HOST_CONFIGURATION.toString(), entry.getTarget());
        assertEquals(MailHostConfigurationChangedEvent.class.getSimpleName(), entry.getAction());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnServerTimeZoneChanged() throws Exception {
        listener.onApplicationConfigurationChanged(new ServerTimeZoneChangedEvent(this, "Europe/Paris", "UTC+01:00"));

        AuditEvent event = getAuditEvent();
        AuditEntry auditEntry = event.getEntry();
        assertContains(auditEntry.getDetails(), "Europe/Paris", "UTC+01:00");
        assertEquals(ApplicationConfigurationChangedEvent.Property.TIME_ZONE.toString(), auditEntry.getTarget());
        assertEquals(ServerTimeZoneChangedEvent.class.getSimpleName(), auditEntry.getAction());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnTicketRejected() throws Exception {
        listener.onTicketRejected(new TicketRejectedEvent(this, "thing"));

        AuditEvent event = getAuditEvent();
        assertEquals("thing", event.getEntry().getDetails());
        assertEquals("thing", event.getEntry().getTarget());
        assertEventCommonDetails(event, Priority.LOW);
    }

    private void assertConfigurationChangedDetails(String expectedOld, String expectedNew, String jsonDetails) {
        JsonObject details = new JsonParser().parse(jsonDetails).getAsJsonObject();
        String oldValue = details.get("old").getAsString();
        String newValue = details.get("new").getAsString();

        assertEquals(expectedOld, oldValue);
        assertEquals(expectedNew, newValue);
    }
}