import com.correx.core.approvals.ApprovalOutcome
import com.correx.core.approvals.ApprovalStatus
import com.correx.core.approvals.GrantScope
import com.correx.core.approvals.Tier
import com.correx.core.approvals.domain.DefaultApprovalEngine
import com.correx.core.approvals.model.ApprovalContext
import com.correx.core.approvals.model.ApprovalGrant
import com.correx.core.approvals.model.ApprovalScopeIdentity
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.SessionId
import com.correx.core.sessions.ApprovalMode
import com.correx.testing.fixtures.request
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 GrantSemanticsTest {

    private val engine = DefaultApprovalEngine()

    @Test
    fun `grant permits exact tier - auto_approved`() {
        val req = request("r1", Tier.T2).copy(toolName = "shell")
        val grant = ApprovalGrant(
            id = GrantId("g1"),
            scope = GrantScope.SESSION(toolName = "shell"),
            permittedTiers = setOf(Tier.T2),
            reason = "test",
            timestamp = Instant.parse("2026-01-01T00:00:00Z")
        )
        val ctx = ApprovalContext(
            ApprovalScopeIdentity(SessionId("s1"), null, null),
            ApprovalMode.DENY
        )
        val now = Instant.parse("2026-01-01T00:00:01Z")

        val decision = engine.evaluate(req, ctx, listOf(grant), now)
        assertEquals(ApprovalOutcome.AUTO_APPROVED, decision.outcome)
        assertEquals(ApprovalStatus.COMPLETED, decision.state)
    }

    @Test
    fun `grant does not permit other tiers`() {
        val req = request("r1", Tier.T3)
        val grant = ApprovalGrant(
            id = GrantId("g1"),
            scope = GrantScope.SESSION(),
            permittedTiers = setOf(Tier.T2),
            reason = "test",
            timestamp = Instant.parse("2026-01-01T00:00:00Z")
        )
        val ctx = ApprovalContext(
            ApprovalScopeIdentity(SessionId("s1"), null, null),
            ApprovalMode.DENY
        )
        val now = Instant.parse("2026-01-01T00:00:01Z")

        val decision = engine.evaluate(req, ctx, listOf(grant), now)
        assertEquals(ApprovalStatus.PENDING, decision.state)
        assertNull(decision.outcome)
    }

    @Test
    fun `multiple grants - any match is enough`() {
        val req = request("r1", Tier.T4).copy(toolName = "write_file")
        val grants = listOf(
            ApprovalGrant(
                GrantId("g1"),
                GrantScope.SESSION(toolName = "shell"),
                setOf(Tier.T3),
                "",
                Instant.parse("2026-01-01T00:00:00Z")
            ),
            ApprovalGrant(
                GrantId("g2"),
                GrantScope.SESSION(toolName = "write_file"),
                setOf(Tier.T4),
                "",
                Instant.parse("2026-01-01T00:00:00Z")
            )
        )
        val ctx = ApprovalContext(
            ApprovalScopeIdentity(SessionId("s1"), null, null),
            ApprovalMode.DENY
        )
        val now = Instant.parse("2026-01-01T00:00:01Z")

        val decision = engine.evaluate(req, ctx, grants, now)
        assertEquals(ApprovalOutcome.AUTO_APPROVED, decision.outcome)
    }
}
