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.ProjectId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
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.Test

class ApprovalEngineEdgeCasesTest {

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

    private fun context(mode: ApprovalMode) = ApprovalContext(
        ApprovalScopeIdentity(SessionId("s1"), StageId("st1"), ProjectId("p1")),
        mode
    )

    @Test
    fun `grants from different scopes apply only to matching identity`() {
        val sessionGrant = ApprovalGrant(
            id = GrantId("g1"),
            scope = GrantScope.SESSION(),
            permittedTiers = setOf(Tier.T3),
            reason = "",
            timestamp = Instant.parse("2026-01-01T00:00:00Z")
        )
        val stageGrant = ApprovalGrant(
            id = GrantId("g2"),
            scope = GrantScope.STAGE(StageId("st2")),
            permittedTiers = setOf(Tier.T4),
            reason = "",
            timestamp = Instant.parse("2026-01-01T00:00:00Z")
        )

        val decision = engine.evaluate(
            request("r1", Tier.T4),
            context(ApprovalMode.DENY),
            listOf(sessionGrant, stageGrant),
            now
        )
        assertEquals(
            ApprovalStatus.PENDING, decision.state,
            "Stage grant for different stage should not apply"
        )
    }

    @Test
    fun `expired grant is ignored`() {
        val past = Instant.parse("2025-12-31T23:59:59Z")
        val expiredGrant = ApprovalGrant(
            id = GrantId("g1"),
            scope = GrantScope.SESSION(),
            permittedTiers = setOf(Tier.T2),
            reason = "",
            timestamp = past,
            expiresAt = past // expired before 'now'
        )
        val decision = engine.evaluate(
            request("r1", Tier.T2),
            context(ApprovalMode.DENY),
            listOf(expiredGrant),
            now
        )
        assertEquals(ApprovalStatus.PENDING, decision.state)
    }

    @Test
    fun `timestamp passed to evaluate is used as resolution timestamp`() {
        val myNow = Instant.parse("2026-07-01T12:00:00Z")
        val decision = engine.evaluate(
            request("r1", Tier.T0),
            context(ApprovalMode.YOLO),
            emptyList(),
            myNow
        )
        assertEquals(myNow, decision.resolutionTimestamp)
    }
}
