import Foundation

/// "Orchestra" — Nucleic's orchestration mode, modeled on Claude Code's ultracode mode.
///
/// Orchestra is *not* an API effort level. It pairs the documented `xhigh` effort with
/// standing consent for the agent to fan work out to parallel subagents (the `Task` /
/// `Workflow` tools) by default. The user selects it in the effort menu like any other
/// level, but it never reaches a backend verbatim:
///
/// - `resolvedEffort` maps the `orchestra` sentinel to its real effort, `xhigh`, so the
///   `claude --effort` (and Codex) flag only ever sees a level the API accepts.
/// - `combinedSystemPrompt` rides the standing-consent text in on `--append-system-prompt`.
///   The CLI doesn't persist that flag, so `SessionController` re-applies it every turn —
///   which is exactly the per-turn "mode reminder" the orchestration design calls for, so
///   no separate refresher counter is needed here.
///
/// Keeping the sentinel, the effort mapping, and the consent text in one place lets the UI,
/// the core, and the tests agree on what "orchestra" means.
public enum OrchestrationMode {
    /// The sentinel stored in `Session.effort` when the user picks Orchestra. Chosen so it
    /// never collides with a real API effort level and is obvious in the persisted store.
    public static let effortSentinel = "orchestra"

    /// The mode's former sentinel, from before it was renamed from "Ultracode". Still
    /// recognized so a session persisted (or in flight from an older remote) under the old
    /// name keeps resolving to the mode rather than being sent to a backend verbatim.
    public static let legacyEffortSentinel = "ultracode"

    /// The real effort level orchestra runs at. The xhigh ceiling is the most thorough the
    /// API documents; orchestra adds the fan-out consent on top, not a hidden higher level.
    public static let resolvedOrchestraEffort = "xhigh"

    /// Whether `effort` selects orchestra (case-insensitive, whitespace-tolerant). Accepts the
    /// legacy "ultracode" token too, so the rename can't strand an already-stored selection.
    public static func isOrchestra(_ effort: String?) -> Bool {
        let normalized = effort?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
        return normalized == effortSentinel || normalized == legacyEffortSentinel
    }

    /// The effort actually handed to a backend: `orchestra` resolves to `xhigh`; everything
    /// else passes through untouched. One-way — the resolved value never flows back into
    /// `Session.effort`, so the UI keeps showing "Orchestra".
    public static func resolvedEffort(_ effort: String?) -> String? {
        isOrchestra(effort) ? resolvedOrchestraEffort : effort
    }

    /// The standing-consent instruction appended to the system prompt while orchestra is on.
    /// It grants the agent blanket permission to orchestrate multi-agent workflows for the
    /// session and points at the fan-out / verification patterns to reach for. Re-sent every
    /// turn by the caller, so it doubles as the mode's recurring reminder.
    ///
    /// The middle paragraph is load-bearing: Orchestra is purely a prompt nudge (Nucleic spawns
    /// no subagents itself — the fan-out is whatever Task calls the model decides to emit), and the
    /// model's most common failure is to *narrate* a fan-out in prose without emitting a single
    /// Task call. So the consent is written imperatively and names that failure mode directly:
    /// claiming to have fanned out without an actual Task call is the one thing it must not do.
    public static let consentPrompt = """
        Orchestra (orchestration mode) is on: optimize for the most exhaustive, correct \
        answer rather than the fastest one, and put maximum thoroughness behind every \
        substantive request. Standing consent: you may fan work out to parallel subagents \
        (the Task tool, or a Workflow/orchestration tool when available) on every substantive \
        task without asking first.

        Make the fan-out real, not narrated. When a task is substantive, actually emit Task \
        tool calls this turn: scout the task yourself, decompose it into independent subtasks \
        sized to the problem's natural structure, and dispatch them as concurrent Task calls, \
        reading their results between phases. Describing a fan-out in prose is not a fan-out — \
        never say you are "fanning out", "delegating", "spawning subagents", or running work \
        "in parallel" unless you have actually issued the corresponding Task tool calls in the \
        same turn. If a turn is conversational or trivial enough that subagents would not help, \
        say so plainly and do the work solo; do not announce an orchestration you are not \
        performing.

        Lean on the quality patterns that fit: adversarial verification (a second wave that \
        tries to refute the first wave's findings against the source), a completeness critic \
        (one agent hunting for what the others missed), and multi-phase sequencing (understand, \
        design, implement, review as separate fan-outs). The fan-out multiplies token usage, so \
        keep each subtask scoped to a distinct concern rather than splitting per line or file.
        """

    /// The system prompt appended for a run: the caller's environment guidance (sandbox build
    /// instructions, etc.) plus, when `effort` selects orchestra, the orchestration consent.
    /// Returns `nil` when neither applies so the backend flag is omitted entirely; joins the
    /// two with a blank line when both are present, so the consent reads as its own paragraph.
    public static func combinedSystemPrompt(environment: String?, effort: String?) -> String? {
        let parts = [environment, isOrchestra(effort) ? consentPrompt : nil]
            .compactMap { $0 }
            .filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }
        return parts.isEmpty ? nil : parts.joined(separator: "\n\n")
    }
}
