package com.livingworld.events;

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

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;

class EventBusTest {

    @Test
    void listenerReceivesPublishedEventExactlyOnce() {
        LivingWorldEventBus bus = new LivingWorldEventBus();
        AtomicInteger calls = new AtomicInteger();
        AtomicReference<LivingWorldEvent> received = new AtomicReference<>();
        BaseLivingWorldEvent event = event("test_event");
        bus.register(event.eventType(), published -> {
            calls.incrementAndGet();
            received.set(published);
        });

        bus.publish(event);

        assertEquals(1, calls.get());
        assertSame(event, received.get());
    }

    @Test
    void multipleListenersReceiveTheSameEvent() {
        LivingWorldEventBus bus = new LivingWorldEventBus();
        AtomicInteger calls = new AtomicInteger();
        bus.register("test_event", event -> calls.incrementAndGet());
        bus.register("test_event", event -> calls.incrementAndGet());
        bus.register("test_event", event -> calls.incrementAndGet());

        bus.publish(event("test_event"));

        assertEquals(3, calls.get());
    }

    @Test
    void unknownEventTypeDoesNotCrash() {
        LivingWorldEventBus bus = new LivingWorldEventBus();

        assertDoesNotThrow(() -> bus.publish(event("unknown")));
        assertEquals(1, bus.getPublishedEventCount());
    }

    private static BaseLivingWorldEvent event(String type) {
        return new BaseLivingWorldEvent(type, 1L, "test");
    }
}
