package com.correx.core.toolintent

import com.correx.core.events.events.ToolRequest
import com.correx.core.events.risk.RiskAction
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.events.types.ToolInvocationId
import com.correx.core.toolintent.rules.WriteScopeRule
import com.correx.core.tools.contract.ToolCapability
import java.nio.file.Path
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class WriteScopeRuleTest {

    private val workspace = Path.of("/work/project")
    private val rule = WriteScopeRule()

    private class FakeProbe : WorldProbe {
        override fun exists(path: Path) = true
        override fun resolveReal(path: Path): Path = path.toAbsolutePath().normalize()
    }

    private fun input(pathArg: String, active: ActiveTask?) = ToolCallAssessmentInput(
        request = ToolRequest(
            ToolInvocationId("i"),
            SessionId("s"),
            StageId("st"),
            "file_write",
            mapOf("path" to pathArg),
        ),
        capabilities = setOf(ToolCapability.FILE_WRITE),
        workspace = WorkspacePolicy(workspace, emptyList()),
        probe = FakeProbe(),
        session = SessionContext(activeTask = active),
    )

    private val scoped = ActiveTask("auth-2", listOf("core/auth/**"))

    @Test
    fun `no active task means nothing to enforce`() {
        assertEquals(
            RiskAction.PROCEED,
            rule.assess(input("/work/project/core/billing/X.kt", active = null)).disposition,
        )
    }

    @Test
    fun `a write inside the claimed task scope proceeds`() {
        val r = rule.assess(input("/work/project/core/auth/Login.kt", scoped))
        assertEquals(RiskAction.PROCEED, r.disposition)
        assertEquals("true", r.observations.single().facts["inScope"])
    }

    @Test
    fun `a write outside the claimed task scope is blocked and names the task`() {
        val r = rule.assess(input("/work/project/core/billing/Charge.kt", scoped))
        assertEquals(RiskAction.BLOCK, r.disposition)
        assertEquals("WRITE_SCOPE", r.issues.single().code)
        assertTrue(r.issues.single().message.contains("auth-2"))
        assertTrue(r.issues.single().message.contains("task_update(id=\"auth-2\""))
        assertTrue(r.issues.single().message.contains("affected_paths=["))
    }
}
