import Foundation
import Testing

@testable import NucleicCore

@Suite("Worktree raw-shell mutation guard")
struct WorktreeMutationGuardTests {
    private func denied(_ command: String) -> Bool {
        WorktreeMutationGuard.denialReason(command: command) != nil
    }

    // MARK: In-place editors

    @Test func flagsInPlaceEditors() {
        #expect(denied("sed -i 's/a/b/' src/main.swift"))
        #expect(denied("sed -i.bak 's/a/b/' file.txt"))
        #expect(denied("sed -e 's/x/y/' -i file.txt"))
        #expect(denied("perl -i -pe 's/a/b/' file"))
        #expect(denied("perl -pi -e 's/a/b/' file"))
        #expect(denied("awk -i inplace '{print}' file"))
        #expect(denied("patch -p1 < changes.diff"))
        #expect(denied("dd of=out.bin if=/dev/zero"))
        #expect(denied("truncate -s 0 log.txt"))
    }

    @Test func allowsStreamEditorsWithoutInPlace() {
        // sed/awk that only read and print are fine unless they redirect to a real file.
        #expect(!denied("sed 's/a/b/' file.txt"))
        #expect(!denied("awk '{print $1}' data.csv"))
        #expect(!denied("grep -n foo file.txt"))
    }

    // MARK: Redirection authoring

    @Test func flagsAuthoringRedirects() {
        #expect(denied("echo 'hello' > greeting.txt"))
        #expect(denied("echo 'x' >> config.yaml"))
        #expect(denied("printf 'a\\nb\\n' > list.txt"))
        #expect(denied("cat > Sources/Foo.swift"))
        #expect(denied("sed 's/a/b/' in.txt > out.txt"))
        #expect(denied("echo x | tee tracked.txt"))
    }

    @Test func flagsHeredocAuthoring() {
        let cmd = "cat > Sources/New.swift <<'EOF'\nlet x = 1\nEOF"
        #expect(denied(cmd))
    }

    @Test func allowsEphemeralRedirects() {
        #expect(!denied("echo 'hi' > /tmp/scratch.txt"))
        #expect(!denied("echo 'hi' > /dev/null"))
        #expect(!denied("cat foo > $TMPDIR/out"))
        #expect(!denied("cat > /tmp/x <<'EOF'\nbody\nEOF"))
        #expect(!denied("echo x | tee /dev/null"))
    }

    @Test func allowsFdAndProcessRedirects() {
        #expect(!denied("make 2>&1"))
        #expect(!denied("some_cmd >&2"))
        #expect(!denied("diff <(sort a) <(sort b)"))
    }

    // MARK: Build/tooling output must not be blocked

    @Test func allowsBuildAndToolOutput() {
        #expect(!denied("make > build.log"))
        #expect(!denied("swift build 2> errors.txt"))
        #expect(!denied("cargo build --release"))
        #expect(!denied("gcc -c foo.c -o foo.o"))
        #expect(!denied("node script.js > result.json"))
        #expect(!denied("npm install"))
    }

    // MARK: Non-mutating commands

    @Test func allowsReadAndVcsCommands() {
        #expect(!denied("git commit -m 'msg'"))
        #expect(!denied("git status"))
        #expect(!denied("ls -la"))
        #expect(!denied("cat README.md"))
        #expect(!denied("rm stale.txt"))  // destructive, but handled by RiskClassifier, not here
    }

    // MARK: Chaining / prefixes

    @Test func inspectsEverySegmentAndStripsPrefixes() {
        #expect(denied("cd Sources && sed -i 's/a/b/' main.swift"))
        #expect(denied("ls; echo x > tracked.txt"))
        #expect(denied("sudo tee /etc/hosts"))
        #expect(denied("FOO=1 BAR=2 sed -i 's/a/b/' file"))
        #expect(!denied("cd Sources && swift build"))
    }

    @Test func reasonNamesCulprit() {
        let reason = WorktreeMutationGuard.denialReason(command: "sed -i 's/a/b/' f")
        #expect(reason?.contains("sed -i") == true)
        #expect(reason?.contains("structured") == true)
    }
}
