package com.correx.core.approvals

import com.correx.core.events.events.ApprovalGrantCreatedEvent
import com.correx.core.events.events.ApprovalGrantExpiredEvent
import com.correx.core.events.events.ApprovalRequestedEvent
import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.NewEvent
import com.correx.core.events.types.ApprovalRequestId
import com.correx.core.events.types.EventId
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.ValidationReportId
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
import com.correx.infrastructure.persistence.InMemoryEventStore
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class DefaultApprovalRepositoryTest {

    private val store = InMemoryEventStore()
    private val replayer = DefaultEventReplayer(store, ApprovalProjector(DefaultApprovalReducer()))
    private val repository = DefaultApprovalRepository(replayer)

    private val timestamp = Instant.parse("2026-01-01T00:00:00Z")

    private fun metadata(sessionId: SessionId, eventId: String): EventMetadata = EventMetadata(
        eventId = EventId(eventId),
        sessionId = sessionId,
        timestamp = timestamp,
        schemaVersion = 1,
        causationId = null,
        correlationId = null
    )

    @Test
    fun `unknown session returns empty ApprovalState`() {
        val state = repository.getApprovalState(SessionId("unknown-session"))
        assertEquals(com.correx.core.approvals.model.ApprovalState(), state)
    }

    @Test
    fun `after ApprovalRequestedEvent state contains the request`(): Unit = runBlocking {
        val sessionId = SessionId("session-requested")
        val requestId = ApprovalRequestId("req-1")

        store.append(
            NewEvent(
                metadata = metadata(sessionId, "event-1"),
                payload = ApprovalRequestedEvent(
                    requestId = requestId,
                    tier = Tier.T2,
                    validationReportId = ValidationReportId("report-1"),
                    riskSummaryId = null,
                    sessionId = sessionId,
                    stageId = null,
                    projectId = null
                )
            )
        )

        val state = repository.getApprovalState(sessionId)
        assertEquals(1, state.requests.size)
        assertTrue(state.requests.containsKey(requestId))
    }

    @Test
    fun `after ApprovalGrantCreatedEvent then ApprovalGrantExpiredEvent grants list is empty`(): Unit = runBlocking {
        val sessionId = SessionId("session-grant-expired")
        val grantId = GrantId("grant-1")

        store.append(
            NewEvent(
                metadata = metadata(sessionId, "event-1"),
                payload = ApprovalGrantCreatedEvent(
                    grantId = grantId,
                    scope = GrantScope.SESSION(),
                    permittedTiers = setOf(Tier.T1, Tier.T2),
                    reason = "approved",
                    expiresAt = null,
                    sessionId = sessionId,
                    stageId = null,
                    projectId = null
                )
            )
        )

        store.append(
            NewEvent(
                metadata = metadata(sessionId, "event-2"),
                payload = ApprovalGrantExpiredEvent(grantId = grantId)
            )
        )

        val state = repository.getApprovalState(sessionId)
        assertTrue(state.grants.isEmpty())
    }
}
