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.StaleWriteRule
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 StaleWriteRuleTest {

    private val workspace = Path.of("/work/project")
    private val rule = StaleWriteRule()
    private val target = "/work/project/src/A.kt"

    private class FakeProbe(private val hashes: Map<Path, String>) : WorldProbe {
        override fun exists(path: Path) = true
        override fun resolveReal(path: Path): Path = path.toAbsolutePath().normalize()
        override fun contentHash(path: Path): String? = hashes[path.toAbsolutePath().normalize()]
    }

    private fun abs(p: String): Path = Path.of(p).toAbsolutePath().normalize()

    private fun input(onDisk: String, session: SessionContext) = ToolCallAssessmentInput(
        request = ToolRequest(
            ToolInvocationId("i"),
            SessionId("s"),
            StageId("st"),
            "file_edit",
            mapOf("path" to target),
        ),
        capabilities = setOf(ToolCapability.FILE_WRITE),
        workspace = WorkspacePolicy(workspace, emptyList()),
        probe = FakeProbe(mapOf(abs(target) to onDisk)),
        session = session,
    )

    @Test
    fun `unchanged since read proceeds`() {
        val r = rule.assess(input(onDisk = "H1", SessionContext(readHashes = mapOf(target to "H1"))))
        assertEquals(RiskAction.PROCEED, r.disposition)
    }

    @Test
    fun `changed on disk since read is blocked`() {
        val r = rule.assess(input(onDisk = "H2", SessionContext(readHashes = mapOf(target to "H1"))))
        assertEquals(RiskAction.BLOCK, r.disposition)
        assertEquals("STALE_WRITE", r.issues.single().code)
    }

    @Test
    fun `a file the session wrote itself is not stale`() {
        val session = SessionContext(readHashes = mapOf(target to "H1"), writes = setOf(target))
        assertEquals(RiskAction.PROCEED, rule.assess(input(onDisk = "H2", session)).disposition)
    }

    @Test
    fun `a file never fully read is not this gate's concern`() {
        assertEquals(RiskAction.PROCEED, rule.assess(input(onDisk = "H2", SessionContext())).disposition)
    }
}
