///|
fn usage() -> String {
  let text =
    #|MoonFlowGraph workflow CLI
    #|
    #|Usage:
    #|  moon run cmd/workflow
    #|  moon run cmd/workflow -- --json ''
    #|  moon run cmd/workflow -- --help
    #|
    #|With no arguments, a built-in research workflow example is imported,
    #|validated, planned, rendered as Mermaid, and exported back to normalized
    #|workflow-spec-v1 JSON.
    #|
  text
}

///|
fn sample_workflow_json() -> String {
  let text =
    #|{
    #|  "schema_version": 1,
    #|  "tasks": [
    #|    {
    #|      "id": "collect_papers",
    #|      "title": "Collect papers",
    #|      "description": "Record the search scope and collect papers for the research question.",
    #|      "outputs": ["search_protocol.md", "paper_index.md"],
    #|      "tags": ["research", "input"]
    #|    },
    #|    {
    #|      "id": "prepare_dataset",
    #|      "title": "Prepare dataset",
    #|      "description": "Freeze the dataset snapshot used by the baseline run.",
    #|      "outputs": ["dataset.parquet", "dataset_card.md"],
    #|      "tags": ["data", "input"]
    #|    },
    #|    {
    #|      "id": "extract_claims",
    #|      "title": "Extract claims",
    #|      "description": "Map paper claims and assumptions to measurable evaluation criteria.",
    #|      "inputs": ["search_protocol.md", "paper_index.md"],
    #|      "outputs": ["claims.json"],
    #|      "tags": ["agent", "analysis"]
    #|    },
    #|    {
    #|      "id": "run_baseline",
    #|      "title": "Run baseline",
    #|      "description": "Run the baseline with a recorded configuration and random seed.",
    #|      "inputs": ["dataset.parquet"],
    #|      "outputs": ["baseline_config.json", "baseline_metrics.json"],
    #|      "tags": ["experiment"]
    #|    },
    #|    {
    #|      "id": "compare_metrics",
    #|      "title": "Compare metrics",
    #|      "description": "Compare results against the criteria extracted from the literature.",
    #|      "inputs": ["claims.json", "baseline_metrics.json"],
    #|      "outputs": ["comparison.md"],
    #|      "tags": ["evaluation"]
    #|    },
    #|    {
    #|      "id": "write_report",
    #|      "title": "Write report",
    #|      "description": "Produce a Markdown handoff report.",
    #|      "inputs": ["comparison.md"],
    #|      "outputs": ["report.md"],
    #|      "tags": ["report"]
    #|    }
    #|  ],
    #|  "dependencies": [
    #|    { "before": "collect_papers", "after": "extract_claims" },
    #|    { "before": "prepare_dataset", "after": "run_baseline" },
    #|    { "before": "extract_claims", "after": "compare_metrics" },
    #|    { "before": "run_baseline", "after": "compare_metrics" },
    #|    { "before": "compare_metrics", "after": "write_report" }
    #|  ]
    #|}
    #|
  text
}

///|
fn parse_input_arg(args : Array[String]) -> Result[String?, String] {
  if args.length() <= 1 {
    return Ok(None)
  }
  let first = args[1]
  if first == "--help" || first == "-h" {
    return Ok(Some("__help__"))
  }
  if first == "--json" {
    if args.length() < 3 {
      return Err("missing value after --json")
    }
    if args.length() > 3 {
      return Err("unexpected extra arguments after --json")
    }
    return Ok(Some(args[2]))
  }
  Err("unknown argument: \{first}")
}

///|
fn join_task_ids(ids : Array[@moonflowgraph.TaskId], sep : String) -> String {
  let out = StringBuilder()
  for i = 0; i < ids.length(); i = i + 1 {
    if i > 0 {
      out.write_string(sep)
    }
    out.write_string(ids[i].value())
  }
  out.to_string()
}

///|
fn write_execution_order(
  out : StringBuilder,
  order : Array[@moonflowgraph.TaskId],
) -> Unit {
  for i = 0; i < order.length(); i = i + 1 {
    out <+ "\{i + 1}. \{order[i].value()}\n"
  }
}

///|
fn write_batches(
  out : StringBuilder,
  batches : Array[Array[@moonflowgraph.TaskId]],
) -> Unit {
  for i = 0; i < batches.length(); i = i + 1 {
    out <+ "- batch \{i + 1}: \{join_task_ids(batches[i], ", ")}\n"
  }
}

///|
fn render_workflow_report(graph : @moonflowgraph.FlowGraph) -> String {
  let roots = match graph.roots() {
    Ok(ids) => ids
    Err(err) => abort("roots: \{err.message()}")
  }
  let leaves = match graph.leaves() {
    Ok(ids) => ids
    Err(err) => abort("leaves: \{err.message()}")
  }
  let plan = match graph.plan() {
    Ok(plan) => plan
    Err(err) => abort("plan: \{err.message()}")
  }
  let mermaid = match graph.to_mermaid() {
    Ok(value) => value
    Err(err) => abort("mermaid: \{err.message()}")
  }
  let workflow_json = graph.to_workflow_spec().to_json()
  let out = StringBuilder()
  out <+ "# MoonFlowGraph Workflow Check\n\n"
  out <+ "- Tasks: \{graph.task_count()}\n"
  out <+ "- Dependencies: \{graph.dependency_count()}\n"
  out <+ "- Roots: \{join_task_ids(roots, ", ")}\n"
  out <+ "- Leaves: \{join_task_ids(leaves, ", ")}\n\n"
  out <+ "## Execution Order\n\n"
  write_execution_order(out, plan.order())
  out <+ "\n## Parallel Batches\n\n"
  write_batches(out, plan.batches())
  out <+ "\n--- MERMAID ---\n"
  out.write_string(mermaid)
  out <+ "--- WORKFLOW JSON ---\n"
  out.write_string(workflow_json)
  out.to_string()
}

///|
fn main {
  let input = match parse_input_arg(@env.args()) {
    Ok(None) => sample_workflow_json()
    Ok(Some(value)) =>
      if value == "__help__" {
        println(usage())
        return
      } else {
        value
      }
    Err(message) => {
      println("argument error: \{message}")
      println(usage())
      abort("invalid workflow CLI arguments")
    }
  }
  let graph = match @moonflowgraph.FlowGraph::from_workflow_json(input) {
    Ok(graph) => graph
    Err(err) => {
      println("workflow import failed: \{err.message()}")
      abort("workflow import failed")
    }
  }
  println(render_workflow_report(graph))
}