import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.NewEvent
import com.correx.core.events.events.SteeringNoteAddedEvent
import com.correx.core.events.events.TransitionExecutedEvent
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.events.types.TransitionId
import com.correx.core.journal.DecisionJournalProjector
import com.correx.core.journal.DecisionJournalRenderer
import com.correx.core.journal.DefaultDecisionJournalReducer
import com.correx.core.journal.DefaultDecisionJournalRepository
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
import com.correx.infrastructure.persistence.InMemoryEventStore
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Clock
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class DecisionJournalReplayTest {

    private fun meta(sessionId: SessionId, id: String) =
        EventMetadata(EventId(id), sessionId, Clock.System.now(), 1, null, null)

    @Test
    fun `journal replay is deterministic`(): Unit = runBlocking {
        val sessionId = SessionId("s")
        val store = InMemoryEventStore()
        store.append(NewEvent(meta(sessionId, "steer"), SteeringNoteAddedEvent(sessionId, "use jwt")))
        store.append(
            NewEvent(
                meta(sessionId, "trans"),
                TransitionExecutedEvent(sessionId, StageId("a"), StageId("b"), TransitionId("t")),
            ),
        )

        val repo = DefaultDecisionJournalRepository(
            DefaultEventReplayer(store, DecisionJournalProjector(DefaultDecisionJournalReducer())),
        )
        val renderer = DecisionJournalRenderer()

        val a = renderer.render(repo.getJournal(sessionId))
        val b = renderer.render(repo.getJournal(sessionId))

        assertEquals(a, b)
        assertTrue(a.contains("use jwt"))
        // TRANSITION records are bookkeeping — deliberately excluded from the render (see
        // DecisionJournalRenderer.AGENT_RELEVANT_KINDS), so "a → b" is intentionally absent.
    }
}
