import Foundation

/// `Decision` → ACP `session/request_permission` outcome (the reply the agent expects). The agent
/// offers `options: [{optionId, name, kind}]` with `kind` ∈ allow_once|allow_always|reject_once|
/// reject_always; we pick the option matching the user's decision and answer
/// `{outcome:"selected", optionId}` — or `{outcome:"cancelled"}` (BACKEND_PROTOCOL §4.1).
///
/// **We never select `allow_always`.** "Always allow" is implemented by *our* `ApprovalCoordinator`
/// cache, which short-circuits matching calls *before* they reach the agent's permission request —
/// so every call grok actually asks about still flows through our handler (and re-runs the conflict
/// pre-check). Selecting the agent's own `allow_always` would let it stop asking and bypass us, so
/// an "always" decision maps to `allow_once` here, exactly like a one-shot allow.
public enum GrokACPDecisionMapping {
    /// The inner `outcome` object for the request's result (the backend wraps it as
    /// `{ "outcome": <this> }`). `.cancelRun` and any unmappable decision answer `cancelled`,
    /// which fail-closed stops the action rather than fabricating a selection.
    public static func permissionOutcome(for decision: Decision, options: [JSONValue]) -> JSONValue {
        func selected(_ id: String) -> JSONValue {
            .object(["outcome": .string("selected"), "optionId": .string(id)])
        }
        let cancelled = JSONValue.object(["outcome": .string("cancelled")])

        switch decision {
        case .allow, .allowAlways:
            return optionId(in: options, preferring: ["allow_once", "allow_always"], family: "allow")
                .map(selected) ?? cancelled
        case .deny:
            return optionId(in: options, preferring: ["reject_once", "reject_always"], family: "reject")
                .map(selected) ?? cancelled
        case .cancelRun:
            return cancelled
        }
    }

    /// First option whose `kind` matches one of `preferring` (in order); else the first whose
    /// `kind` starts with `family` (tolerates an agent that offers only, say, `allow_always`).
    private static func optionId(
        in options: [JSONValue], preferring kinds: [String], family: String
    ) -> String? {
        for kind in kinds {
            if let id = options.first(where: { $0["kind"]?.stringValue == kind })?["optionId"]?.stringValue {
                return id
            }
        }
        return options.first(where: { ($0["kind"]?.stringValue ?? "").hasPrefix(family) })?["optionId"]?
            .stringValue
    }
}
