package com.correx.core.sessions

import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.InitialIntentEvent
import com.correx.core.events.events.SessionNamedEvent
import com.correx.core.events.events.StoredEvent
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 kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test

class SessionSummaryProjectorTest {

    private val projector = SessionSummaryProjector()
    private val sessionId = SessionId("s1")

    private fun stored(
        payload: com.correx.core.events.events.EventPayload,
        eventId: String = "e1",
        timestamp: Instant = Instant.parse("2026-01-01T00:00:00Z"),
        sequence: Long = 1L,
    ) = StoredEvent(
        metadata = EventMetadata(
            eventId = EventId(eventId),
            sessionId = sessionId,
            timestamp = timestamp,
            schemaVersion = 1,
            causationId = null,
            correlationId = null,
        ),
        sequence = sequence,
        sessionSequence = sequence,
        payload = payload,
    )

    @Test
    fun `empty event list produces zeroed summary`() {
        val summary = projector.project(sessionId, emptyList())

        assertEquals(sessionId, summary.sessionId)
        assertNull(summary.intent)
        assertNull(summary.workflowId)
        assertNull(summary.createdAt)
        assertNull(summary.lastActivityAt)
        assertEquals(0, summary.stageCount)
    }

    @Test
    fun `InitialIntentEvent populates intent`() {
        val event = stored(InitialIntentEvent(sessionId, "add auth layer"), eventId = "e1")

        val summary = projector.project(sessionId, listOf(event))

        assertEquals("add auth layer", summary.intent)
    }

    @Test
    fun `SessionNamedEvent surfaces the human name in the summary`() {
        val event = stored(SessionNamedEvent(sessionId, "Add auth layer", timestampMs = 0L))

        val summary = projector.project(sessionId, listOf(event))

        assertEquals("Add auth layer", summary.name)
    }

    @Test
    fun `two TransitionExecutedEvents yield stageCount of two`() {
        val t1 = stored(
            TransitionExecutedEvent(sessionId, StageId("s1"), StageId("s2"), TransitionId("t1")),
            eventId = "e1", sequence = 1L,
        )
        val t2 = stored(
            TransitionExecutedEvent(sessionId, StageId("s2"), StageId("s3"), TransitionId("t2")),
            eventId = "e2", sequence = 2L,
        )

        val summary = projector.project(sessionId, listOf(t1, t2))

        assertEquals(2, summary.stageCount)
    }

    @Test
    fun `createdAt is first event timestamp and lastActivityAt is last event timestamp`() {
        val first = Instant.parse("2026-01-01T10:00:00Z")
        val last = Instant.parse("2026-01-01T11:00:00Z")
        val e1 = stored(InitialIntentEvent(sessionId, "intent"), eventId = "e1", timestamp = first, sequence = 1L)
        val e2 = stored(
            TransitionExecutedEvent(sessionId, StageId("a"), StageId("b"), TransitionId("t1")),
            eventId = "e2", timestamp = last, sequence = 2L,
        )

        val summary = projector.project(sessionId, listOf(e1, e2))

        assertEquals(first, summary.createdAt)
        assertEquals(last, summary.lastActivityAt)
    }
}
