///|
fn inherited_options(
  inherited : ArrayView[OptionDef],
  command : CommandDef,
) -> Array[OptionDef] {
  inherited.to_owned() + command.options[:].filter(option => option.global)
}

///|
// Use argparse's own help routing to preserve inherited argument ordering.
// These are synthetic, validated command paths, never the caller's argv.
fn parser_help_at_path(
  parser : @argparse.Command,
  path : ArrayView[String],
) -> String? {
  if path.is_empty() {
    return Some(parser.render_help())
  }
  match parser.parse_outcome(argv=["help"] + path.to_owned()) {
    Help(text) => Some(text + "\n")
    _ => None
  }
}

///|
fn render_command_help(command : CommandDef, base : String) -> String {
  let extra : Array[String] = []
  if !command.subcommands.is_empty() {
    let locals = command.options.filter(option => {
      option.required && !option.global
    })
    if !locals.is_empty() {
      let names = locals.map(option => "--\{option.name}").join(", ")
      let notice = command.required_scope_notice.unwrap_or(
        "Local required options (\{names}) apply only to this command's own execution. Subcommands require their own local options and inherited globals.",
      )
      if !notice.is_empty() {
        extra.push(notice)
      }
    }
  }
  if !command.examples.is_empty() {
    extra.push("Examples:\n  \{command.examples.join("\n  ")}")
  }
  if extra.is_empty() {
    base
  } else {
    "\{base}\n\{extra.join("\n\n")}\n"
  }
}

///|
// Match complete help generated by the same parser, not diagnostic wording or
// categories. Preserve unfamiliar upstream output without aborting. Synthetic
// help routing avoids re-parsing caller input and preserves inherited ordering.
fn restore_help_for_command(
  app : CliApp,
  parser : @argparse.Command,
  command : CommandDef,
  path : ArrayView[String],
  text : String,
  help_only~ : Bool,
) -> String? {
  if parser_help_at_path(parser, path) is Some(raw) {
    let prefix = if help_only {
      if text == raw.strip_suffix("\n").unwrap_or(raw[:]).to_owned() {
        Some("")
      } else {
        None
      }
    } else {
      text.strip_suffix(raw).map(prefix => prefix.to_owned())
    }
    if prefix is Some(prefix) {
      let annotated = build_parser(app.root, version=app.version)
      if parser_help_at_path(annotated, path) is Some(base) {
        let rendered = render_command_help(command, base)
        return Some(
          if help_only {
            rendered.strip_suffix("\n").unwrap_or(rendered[:]).to_owned()
          } else {
            "\{prefix}\{rendered}"
          },
        )
      }
    }
  }
  for child in command.subcommands {
    if restore_help_for_command(
        app,
        parser,
        child,
        path.to_owned() + [child.name],
        text,
        help_only~,
      )
      is Some(rendered) {
      return Some(rendered)
    }
  }
  None
}

///|
fn restore_parser_help(
  app : CliApp,
  text : String,
  help_only~ : Bool,
) -> String {
  let parser = build_parser(app.root, version=app.version, defer_required=true)
  restore_help_for_command(app, parser, app.root, [], text, help_only~).unwrap_or(
    text,
  )
}

///|
/// Renders root or nested help, including inherited globals and explicit
/// examples, without caller argv or execution. Unknown paths raise UnknownCommand.
pub fn CliApp::render_help(
  self : CliApp,
  command_path~ : ArrayView[String] = [],
) -> String raise CliError {
  let (selected, globals) = for
    name in command_path
    command = self.root, globals = [] {
    guard find_command_def(command.subcommands, name) is Some(child) else {
      raise CliError::UnknownCommand(command_path.to_owned())
    }
    continue child, inherited_options(globals, command)
  } nobreak {
    (command, globals)
  }
  let parser = build_parser(self.root, version=self.version)
  let base = parser_help_at_path(parser, command_path).unwrap_or_else(() => {
    // Defensive fallback if a future upstream changes synthetic help routing.
    let path = ([self.root.name] + command_path.to_owned()).join(" ")
    let version = if command_path.is_empty() {
      Some(self.version)
    } else {
      None
    }
    build_parser(
      {
        ..selected,
        name: path,
        options: ReadOnlyArray::from_array(
          globals + selected.options[:].to_owned(),
        ),
      },
      version?,
    ).render_help()
  })
  render_command_help(selected, base)
}