package com.correx.core.sessions.projections

import com.correx.core.events.events.EgressHostsGrantedEvent
import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.InitialIntentEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import kotlinx.datetime.Instant
import kotlin.test.Test
import kotlin.test.assertEquals

class EgressAllowlistProjectionTest {

    private val sessionId = SessionId("s1")
    private val projection = EgressAllowlistProjection(sessionId)

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

    private fun fold(vararg events: StoredEvent): Set<String> =
        events.fold(projection.initial()) { acc, e -> projection.apply(acc, e) }

    @Test
    fun `initial state is empty`() {
        assertEquals(emptySet(), projection.initial())
    }

    @Test
    fun `grants fold into a union`() {
        val result = fold(
            stored(EgressHostsGrantedEvent(sessionId, setOf("a.com", "b.com")), "e1"),
            stored(EgressHostsGrantedEvent(sessionId, setOf("b.com", "c.com")), "e2"),
        )
        assertEquals(setOf("a.com", "b.com", "c.com"), result)
    }

    @Test
    fun `grants for other sessions are ignored`() {
        val result = fold(
            stored(EgressHostsGrantedEvent(sessionId, setOf("mine.com")), "e1"),
            stored(EgressHostsGrantedEvent(SessionId("other"), setOf("theirs.com")), "e2"),
        )
        assertEquals(setOf("mine.com"), result)
    }

    @Test
    fun `unrelated events are ignored`() {
        val result = fold(
            stored(InitialIntentEvent(sessionId, "do a thing"), "e1"),
            stored(EgressHostsGrantedEvent(sessionId, setOf("kept.com")), "e2"),
        )
        assertEquals(setOf("kept.com"), result)
    }
}
