///|
/// The agent-facing docx CLI, structured like `cmd/xlsx`: one binary, one
/// subcommand per operation. Subcommands:
///
///   docx create                     create a blank document
///   docx batch         author a document from ops
///   docx convert  [output] [flags]   convert to HTML or Markdown
///   docx outline                      print a document map as JSON
///   docx text                         print path-tagged plain text
///   docx get   [--json]         print one element by path
///   docx validate                     check package structure
///
/// The `convert` subcommand is the same operation as the published
/// `docx2html` binary (both call the shared runner in `internal/cli`); this
/// binary is where the structured read/validate/authoring surface grows.
/// Subcommand handlers live in `commands_convert.mbt` (one file per command
/// family, so later commands don't collide in review).
async fn main {
  run_cli() catch {
    // A `CliError` is already a formatted, user-facing message. Reader errors
    // get the `docx:` program prefix; anything else keeps argparse's own
    // `error:` prefix or gains `docx:`. The error escapes `main`, which
    // prints once and exits non-zero. Since async 0.21, native uses stderr;
    // wasm still uses stdout.
    @cli.CliError(_) as err => raise err
    @docx2html.InvalidZip(message~)
    | @docx2html.InvalidXml(message~)
    | @docx2html.MissingPart(message~)
    | @docx2html.Unsupported(message~)
    | @docx2html.ResourceLimit(message~, ..) =>
      raise @cli.CliError("docx: " + message)
    err => {
      let msg = err.to_string()
      raise @cli.CliError(
        if msg.has_prefix("error:") {
          msg
        } else {
          "docx: " + msg
        },
      )
    }
  }
}

///|
/// Parses arguments and dispatches to the selected subcommand. Argument
/// errors from `parse` propagate to `main`.
async fn run_cli() -> Unit {
  let argv = @env.args()
  let args = if argv.length() > 0 { argv[1:].to_owned() } else { [] }
  let command = build_command()
  let matches = command.parse(argv=args, env=Map([]))
  match matches.subcommand {
    Some(("create", m)) => run_create(m)
    Some(("batch", m)) => run_batch(m)
    Some(("convert", m)) => run_convert(m)
    Some(("outline", m)) => run_outline(m)
    Some(("text", m)) => run_text(m)
    Some(("get", m)) => run_get(m)
    Some(("validate", m)) => run_validate(m)
    Some(("annotate", m)) =>
      match m.subcommand {
        Some(("add", mm)) => run_annotate_add(mm)
        Some(("reply", mm)) => run_annotate_reply(mm)
        Some(("resolve", mm)) => run_annotate_resolution(mm, true)
        Some(("unresolve", mm)) => run_annotate_resolution(mm, false)
        _ => println(command.render_help())
      }
    _ => println(command.render_help())
  }
}

///|
/// Builds the argparse command tree.
fn build_command() -> @argparse.Command {
  Command(
    "docx",
    about="Read, inspect, and convert docx documents",
    subcommand_required=true,
    subcommands=[
      create_command(),
      batch_command(),
      convert_command(),
      outline_command(),
      text_command(),
      get_command(),
      validate_command(),
      annotate_command(),
    ],
  )
}