package com.correx.testing.contracts.fixtures.projections

import com.correx.core.events.stores.EventStore
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.core.sessions.SessionCounterState
import com.correx.core.sessions.projections.replay.EventReplayer
import com.correx.testing.fixtures.EventFixtures.newEvent
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

abstract class SessionReplayContractTest {

    protected abstract fun store(): EventStore

    protected abstract fun replayer(
        store: EventStore
    ): EventReplayer<SessionCounterState>

    @Test
    fun `rebuild is deterministic`(): Unit = runBlocking {
        val store = store()

        repeat(50) {
            store.append(newEvent(EventId("e$it"), SessionId("s1")))
        }

        val replayer = replayer(store)

        val state1 = replayer.rebuild(SessionId("s1"))
        val state2 = replayer.rebuild(SessionId("s1"))

        assertEquals(state1, state2)
    }

    @Test
    fun `rebuild reflects complete stream`(): Unit = runBlocking {
        val store = store()

        repeat(42) {
            store.append(newEvent(EventId("e$it"), SessionId("s1")))
        }

        val replayer = replayer(store)

        val state = replayer.rebuild(SessionId("s1"))

        assertEquals(42, state.count)
    }
}