///|
fn parser() -> @clap.Parser {
  @clap.Parser::new(
    prog="uc",
    description="Convert unit-bearing quantities with LunarUnits.",
    args={
      "format": @clap.Arg::named(
        short='f',
        nargs=Fixed(1),
        choices=@hashset.from_array(["ascii", "si", "latex"]),
        defaults=["ascii"],
        global=true,
        help="Output format: ascii, si, or latex",
      ),
    },
    subcmds={
      "convert": @clap.SubCommand::new(
        args={
          "input": @clap.Arg::positional(
            nargs=Fixed(2),
            help="Quantity expression and target unit",
          ),
        },
        help="Convert a quantity to a target unit",
      ),
      "parse": @clap.SubCommand::new(
        args={
          "expr": @clap.Arg::positional(
            nargs=Fixed(1),
            help="Quantity expression",
          ),
        },
        help="Parse a quantity expression",
      ),
      "parse-unit": @clap.SubCommand::new(
        args={
          "expr": @clap.Arg::positional(nargs=Fixed(1), help="Unit expression"),
        },
        help="Parse a unit expression",
      ),
      "inspect": @clap.SubCommand::new(
        args={
          "symbol": @clap.Arg::positional(nargs=Fixed(1), help="Unit symbol"),
        },
        help="Inspect a unit symbol",
      ),
    },
  )
}

///|
fn args_without_program() -> Array[String] {
  let args = @env.args()
  if args.length() > 0 &&
    (
      args[0].contains("/") ||
      args[0].contains("\\") ||
      args[0].contains(".exe")
    ) {
    let trimmed = []
    for i in 1.. Bool {
  arg == "convert" || arg == "parse" || arg == "parse-unit" || arg == "inspect"
}

///|
fn extract_format(args : Array[String]) -> (String, Array[String]) {
  let mut format = "ascii"
  let rest = []
  let mut i = 0
  while i < args.length() {
    if (args[i] == "--format" || args[i] == "-f") && i + 1 < args.length() {
      format = args[i + 1]
      i = i + 2
    } else {
      rest.push(args[i])
      i = i + 1
    }
  }
  (format, rest)
}

///|
fn should_use_clap(args : Array[String]) -> Bool {
  args.is_empty() || is_known_subcommand(args[0])
}

///|
fn run_convert_shortcut(args : Array[String]) -> @lib.CliResult {
  let (format, rest) = extract_format(args)
  guard rest.length() == 2 else {
    return Err("usage: uc [--format ascii|si|latex]  ")
  }
  @lib.run_convert(rest[0], rest[1], format~)
}

///|
fn root_help() -> String {
  (
    #|Usage: uc [OPTIONS]  
    #|       uc  [OPTIONS]
    #|
    #|Commands:
    #|  convert     Convert a quantity to a target unit
    #|  parse       Parse a quantity expression
    #|  parse-unit  Parse a unit expression
    #|  inspect     Inspect a unit symbol
    #|
    #|Options:
    #|  -f, --format   Output format: ascii, si, or latex
    #|  -h, --help             Print help
    #|
  )
}

///|
fn print_result(result : @lib.CliResult) -> Unit {
  match result {
    Ok(output) => println(output)
    Err(message) => println("error: \{message}")
  }
}

///|
fn selected_format(value : @clap.SimpleValue) -> String {
  value.get_option("format").unwrap_or("ascii") catch {
    _ => "ascii"
  }
}

///|
fn run(value : @clap.SimpleValue) -> @lib.CliResult {
  let format = selected_format(value)
  match value.subcmd {
    Some(subcmd) =>
      match subcmd.name {
        "convert" => {
          let args : Array[String] = subcmd.get_positional() catch {
            err => return Err("invalid convert arguments: \{err}")
          }
          @lib.run_convert(args[0], args[1], format~)
        }
        "parse" => {
          let args : Array[String] = subcmd.get_positional() catch {
            err => return Err("invalid parse arguments: \{err}")
          }
          @lib.run_parse(args[0], format~)
        }
        "parse-unit" => {
          let args : Array[String] = subcmd.get_positional() catch {
            err => return Err("invalid parse-unit arguments: \{err}")
          }
          @lib.run_parse_unit(args[0], format~)
        }
        "inspect" => {
          let args : Array[String] = subcmd.get_positional() catch {
            err => return Err("invalid inspect arguments: \{err}")
          }
          @lib.run_inspect(args[0], format~)
        }
        _ => Err("unknown subcommand: \{subcmd.name}")
      }
    None => Err("usage: uc  ")
  }
}

///|
fn main {
  let raw_args = args_without_program()
  if raw_args.length() == 1 && (raw_args[0] == "--help" || raw_args[0] == "-h") {
    println(root_help())
    return
  }
  if !should_use_clap(raw_args) {
    print_result(run_convert_shortcut(raw_args))
    return
  }
  let parser = parser()
  let value = @clap.SimpleValue::new("uc")
  let help = parser.parse(value, raw_args) catch {
    err => {
      println("error: \{err}")
      return
    }
  }
  match help {
    Some(message) => println(message)
    None => print_result(run(value))
  }
}