///|
/// A WORKFLOW SCRIPT: the shape a generated or hand-written orchestration
/// takes. Its whole dependency closure is `moonbitlang/workflow` (plus its
/// `spawn` sub-package) — the engine is just a binary path in argv[1]
/// that speaks the child contract.
///
///   moon run workflow/examples/scout --  [--journal j.jsonl] [--kind k] [--model m]
///
/// With no kind, three `run --kind echo` probes run keylessly. With
/// `--kind explore` (and optionally a model name), one real read-only
/// scout answers a question about the repository — the provider key rides
/// the inherited environment, exactly as the contract prescribes. Run
/// twice with a journal path to watch the second generation replay from
/// the journal instead of spawning any children.
async fn main {
  let spec = @argparse.Command(
    "scout",
    about="Run a few probes through an engine that speaks the child contract.",
    arg_required_else_help=true,
    options=[
      @argparse.OptionArg(
        "journal",
        about="journal to record into and replay from (default: in memory)",
      ),
      @argparse.OptionArg("kind", about="the call kind the engine dispatches", default_values=[
        "echo",
      ]),
      @argparse.OptionArg("model", about="engine setting, forwarded in argv"),
    ],
    positionals=[
      @argparse.PositionArg(
        "engine",
        about="the engine binary to spawn",
        num_args=@argparse.ValueRange::single(),
      ),
    ],
  )
  // Parse failures and `--help` carry their own contextual help text.
  let args = spec.parse() catch {
    error => {
      println("\{error}")
      return
    }
  }
  guard first(args, "engine") is Some(exe) else { return }
  let journal = match first(args, "journal") {
    Some(path) => @workflow.Journal::load(path)
    None => @workflow.Journal::in_memory()
  }
  let kind = first(args, "kind").unwrap_or("echo")
  let model = first(args, "model")
  let wf = @workflow.Workflow(
    runner=@spawn.contract_runner(launch=call => {
      // The script owns its launch: the REQUEST already carries the kind
      // and the step ceiling, so argv holds only engine settings — and the
      // kind, which `openseek run` checks against the request's. The API
      // key is NEVER here — it rides the inherited environment. Each child
      // writes one result file where the runner puts `{result_file}`.
      let argv = [
        "run",
        "--input-format",
        "json",
        "--cancel-on-stdin-eof",
        "--kind",
        call.kind,
        "--result-file",
        @spawn.ResultFilePlaceholder,
      ]
      if model is Some(model) {
        argv.push("--model")
        argv.push(model)
      }
      @spawn.LaunchSpec(command=exe, args=argv)
    }),
    max_concurrent=4,
    max_calls=16,
    journal~,
    on_event=event => {
      match event {
        @workflow.AgentStarted(label~, ..) => println("  ▶ \{label}")
        @workflow.AgentReplayed(label~, ..) =>
          println("  ↺ \{label} (replayed)")
        _ => ()
      }
    },
  )
  wf.phase("Scout")
  let results = if kind == "echo" {
    // Three keyless probes; each is one child process of the engine.
    @workflow.fan_out(["alpha", "beta", "gamma"], probe => {
      @workflow.attempt(() => {
        wf.agent(prompt="probe \{probe}", kind="echo", label="scout:\{probe}")
      })
    })
  } else {
    // One REAL scout: a model-driven read-only agent over this
    // repository, bounded by a small step ceiling.
    [
      @workflow.attempt(() => {
        wf.agent(
          prompt="What presets does `openseek run --kind` dispatch, and where is the dispatch? Answer in one sentence.",
          kind~,
          hints="internal/openseek/run",
          label="scout:run-kinds",
          max_steps=24,
        )
      }),
    ]
  }
  // Report per slot: a failed agent is a printed line, not a crash —
  // the typed error channel makes the choice explicit.
  for result in results {
    match result {
      Ok(answer) => println("  report: \{answer.stringify()}")
      Err(error) => println("  FAILED: \{error}")
    }
  }
  println(
    "launched \{wf.calls_made()} children, replayed \{wf.calls_replayed()}, spent \{wf.tokens_spent()} tokens",
  )
}

///|
/// The first value parsed for an argument, if it was given at all.
fn first(args : @argparse.Matches, name : String) -> String? {
  match args.values.get(name) {
    Some([value, ..]) => Some(value)
    _ => None
  }
}