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.ShellInFileContentRule
import com.correx.core.tools.contract.ToolCapability
import java.nio.file.Path
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class ShellInFileContentRuleTest {

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

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

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

    @Test
    fun `applies only to FILE_WRITE`() {
        assertTrue(rule.appliesTo(setOf(ToolCapability.FILE_WRITE)))
        assertFalse(rule.appliesTo(setOf(ToolCapability.FILE_READ)))
    }

    @Test
    fun `a source file whose content is a bare mkdir command is blocked`() {
        val r = rule.assess(input("frontend/src/components/tasks", "mkdir -p frontend/src/components/tasks"))
        assertEquals(RiskAction.BLOCK, r.disposition)
        assertEquals("SHELL_IN_FILE", r.issues.single().code)
        assertTrue(r.issues.single().message.contains("parents are auto-created"))
    }

    @Test
    fun `a real tsx file proceeds`() {
        val content = "export function Tasks() {\n  return <div>tasks</div>;\n}\n"
        val r = rule.assess(input("frontend/src/components/tasks.tsx", content))
        assertEquals(RiskAction.PROCEED, r.disposition)
        assertTrue(r.issues.isEmpty())
    }

    @Test
    fun `a real shell script starting with a shell verb is exempt`() {
        val r = rule.assess(input("scripts/setup.sh", "mkdir -p build\ncp foo build/"))
        assertEquals(RiskAction.PROCEED, r.disposition)
    }

    @Test
    fun `a single-line shell script is exempt by extension`() {
        val r = rule.assess(input("scripts/mk.sh", "mkdir -p build"))
        assertEquals(RiskAction.PROCEED, r.disposition)
    }

    @Test
    fun `a README with a multi-line mkdir code block proceeds`() {
        val content = "# Setup\n\n```sh\nmkdir -p build\n```\n"
        val r = rule.assess(input("README.md", content))
        assertEquals(RiskAction.PROCEED, r.disposition)
    }

    @Test
    fun `an extensionless Makefile is exempt`() {
        val r = rule.assess(input("Makefile", "mkdir -p build"))
        assertEquals(RiskAction.PROCEED, r.disposition)
    }
}
