package com.atlassian.bitbucket.internal.mirroring.mirror.rest.webhook;

import com.atlassian.bitbucket.internal.mirroring.mirror.rest.RestUnknownEntity;
import com.atlassian.bitbucket.internal.mirroring.mirror.rest.webhook.cloud.CloudWebHookEventId;
import com.atlassian.bitbucket.internal.mirroring.mirror.rest.webhook.cloud.RestCloudRepositoryPushWebHookEvent;
import com.atlassian.bitbucket.internal.mirroring.mirror.rest.webhook.server.*;
import com.atlassian.bitbucket.internal.mirroring.mirror.webhook.CloudWebHookEvent;
import com.atlassian.bitbucket.internal.mirroring.mirror.webhook.ServerWebHookEvent;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Collections;
import java.util.Optional;

import static com.atlassian.bitbucket.mirroring.mirror.UpstreamServerType.BITBUCKET_CLOUD;
import static com.atlassian.bitbucket.mirroring.mirror.UpstreamServerType.BITBUCKET_SERVER;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@RunWith(MockitoJUnitRunner.class)
public class DefaultRestWebHookEventConverterTest {

    @InjectMocks
    private DefaultRestWebHookEventConverter converter;

    @Test
    public void testServerEventIdMappings() throws Exception {
        assertServerMappingForId(ServerWebHookEventId.REPOSITORY_CREATED, RestServerRepositoryCreatedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.REPOSITORY_REFS_CHANGED, RestServerRepositoryRefsChangedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.REPOSITORY_MODIFIED, RestServerRepositoryModifiedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.REPOSITORY_DELETED, RestServerRepositoryDeletedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.PROJECT_MODIFIED, RestServerProjectModifiedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.PROJECT_CREATED, RestServerProjectCreatedWebHookEvent.class);
        assertServerMappingForId(ServerWebHookEventId.PROJECT_DELETED, RestServerProjectDeletedWebHookEvent.class);
    }

    @Test
    public void testCloudEventIdMappings() throws Exception {
        assertCloudMappingForId(CloudWebHookEventId.REPOSITORY_PUSH, RestCloudRepositoryPushWebHookEvent.class);
    }

    @Test
    public void testUnknownCloudEventIdMapping() throws Exception {
        assertFalse(converter.convert(BITBUCKET_CLOUD, new RestUnknownEntity(ImmutableMap.of("event", "unknown"))).isPresent());
    }

    @Test
    public void testNoCloudEventIdMapping() throws Exception {
        assertFalse(converter.convert(BITBUCKET_CLOUD, new RestUnknownEntity()).isPresent());
    }

    @Test
    public void testUnknownServerEventIdMapping() throws Exception {
        assertFalse(converter.convert(BITBUCKET_SERVER, new RestUnknownEntity(ImmutableMap.of("eventKey", "unknown"))).isPresent());
    }

    @Test
    public void testNoServerEventIdMapping() throws Exception {
        assertFalse(converter.convert(BITBUCKET_SERVER, new RestUnknownEntity(Collections.emptyMap())).isPresent());
    }

    private void assertCloudMappingForId(CloudWebHookEventId webHookEventId, Class<? extends CloudWebHookEvent> eventClass) {
        Optional<? extends BaseRestWebHookEvent> event = converter.convert(
                BITBUCKET_CLOUD,
                new RestUnknownEntity(ImmutableMap.of("event", webHookEventId.getValue(), "data", Collections.emptyMap())));
        assertTrue(event.isPresent());
        assertTrue(eventClass.isAssignableFrom(event.get().getClass()));
    }

    private void assertServerMappingForId(ServerWebHookEventId webHookEventId, Class<? extends ServerWebHookEvent> eventClass) {
        Optional<? extends BaseRestWebHookEvent> event = converter.convert(
                BITBUCKET_SERVER,
                new RestUnknownEntity(ImmutableMap.of("eventKey", webHookEventId.getValue())));
        assertTrue(event.isPresent());
        assertTrue(eventClass.isAssignableFrom(event.get().getClass()));
    }
}