package p.studio.lsp.events;

import org.junit.jupiter.api.Test;
import p.studio.workspaces.WorkspaceId;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import static org.junit.jupiter.api.Assertions.assertEquals;

final class StudioWorkspaceEventBusTest {
    @Test
    void workspaceEventsAreObservedLocallyAndGlobally() {
        final StudioEventBus globalBus = new StudioEventBus();
        final StudioWorkspaceEventBus workspaceBus = new StudioWorkspaceEventBus(WorkspaceId.ASSETS, globalBus);
        final List<String> localReceived = new CopyOnWriteArrayList<>();
        final List<String> globalReceived = new CopyOnWriteArrayList<>();

        workspaceBus.subscribe(TestStudioEvent.class, event -> localReceived.add(event.name()));
        globalBus.subscribe(TestStudioEvent.class, event -> globalReceived.add(event.name()));

        workspaceBus.publish(new TestStudioEvent("asset-discovered"));

        assertEquals(List.of("asset-discovered"), localReceived);
        assertEquals(List.of("asset-discovered"), globalReceived);
    }

    @Test
    void globalEventsAreNotRebroadcastBackIntoWorkspaceBus() {
        final StudioEventBus globalBus = new StudioEventBus();
        final StudioWorkspaceEventBus workspaceBus = new StudioWorkspaceEventBus(WorkspaceId.ASSETS, globalBus);
        final List<String> localReceived = new CopyOnWriteArrayList<>();
        final List<String> globalReceived = new CopyOnWriteArrayList<>();

        workspaceBus.subscribe(TestStudioEvent.class, event -> localReceived.add(event.name()));
        globalBus.subscribe(TestStudioEvent.class, event -> globalReceived.add(event.name()));

        globalBus.publish(new TestStudioEvent("global-only"));

        assertEquals(List.of(), localReceived);
        assertEquals(List.of("global-only"), globalReceived);
    }

    @Test
    void projectLoadingProgressEventsCanFlowThroughTheStudioBus() {
        final StudioEventBus globalBus = new StudioEventBus();
        final StudioWorkspaceEventBus workspaceBus = new StudioWorkspaceEventBus(WorkspaceId.ASSETS, globalBus);
        final List<StudioProjectLoadingPhase> globalReceived = new CopyOnWriteArrayList<>();

        globalBus.subscribe(StudioProjectLoadingProgressEvent.class, event -> globalReceived.add(event.phase()));

        workspaceBus.publish(new StudioProjectLoadingProgressEvent(
                StudioProjectLoadingPhase.INITIALIZING_SERVICES,
                "Initializing services",
                0.5d,
                false));

        assertEquals(List.of(StudioProjectLoadingPhase.INITIALIZING_SERVICES), globalReceived);
    }

    private record TestStudioEvent(String name) implements StudioEvent {
    }
}
