import Foundation
import Testing

@testable import NucleicCore

/// Tier-0 decision mapping (OBSERVABILITY B.3): every Decision → the exact
/// native reply bytes (BACKEND_PROTOCOL §4.1, source-confirmed shapes).
@Suite struct DecisionMappingTests {
    let originalInput: JSONValue = ["command": "rm -rf build/"]

    @Test func allowEchoesOriginalInput() {
        let reply = ClaudeDecisionMapping.reply(for: .allow(), originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"allow","updatedInput":{"command":"rm -rf build/"}}"#)
    }

    @Test func allowWithRewrittenInput() {
        let reply = ClaudeDecisionMapping.reply(
            for: .allow(updatedInput: ["command": "rm -rf build/tmp"]),
            originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"allow","updatedInput":{"command":"rm -rf build/tmp"}}"#)
    }

    @Test func allowAlwaysMapsToPlainAllow() {
        let reply = ClaudeDecisionMapping.reply(
            for: .allowAlways(.toolName), originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"allow","updatedInput":{"command":"rm -rf build/"}}"#)
    }

    @Test func denyCarriesMessageNotReason() {
        let reply = ClaudeDecisionMapping.reply(
            for: .deny(reason: "publish not permitted"), originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"deny","message":"publish not permitted"}"#)
    }

    @Test func denyWithoutReasonGetsDefaultMessage() {
        let reply = ClaudeDecisionMapping.reply(for: .deny(reason: nil), originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"deny","message":"Denied by user"}"#)
    }

    @Test func cancelRunMapsToDeny() {
        let reply = ClaudeDecisionMapping.reply(for: .cancelRun, originalInput: originalInput)
        #expect(reply.wireJSON() == #"{"behavior":"deny","message":"Run canceled by user"}"#)
    }
}
