///|
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.. (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 root_help() -> String {
  (
    #|Usage: fc [OPTIONS] 
    #|
    #|Commands:
    #|  list                  List available formulas
    #|  show            Show formula metadata and inputs
    #|  calc  [INPUTS]  Calculate a formula
    #|
    #|Options:
    #|  -f, --format   Output format: ascii, si, or latex
    #|  -h, --help             Print help
    #|
    #|Example:
    #|  fc calc force --mass "2 kg" --acceleration "3 m/s^2"
    #|
  )
}

///|
fn drop_option_prefix(name : String) -> String {
  let chars : Array[Char] = []
  let mut start = 0
  let source : Array[Char] = []
  name.iter().each(fn(c) { source.push(c) })
  while start < source.length() && source[start] == '-' {
    start += 1
  }
  for i in start.. Array[@lib.InputBinding]? {
  let bindings : Array[@lib.InputBinding] = []
  let mut i = start
  while i < args.length() {
    if !(args[i].contains("--") && i + 1 < args.length()) {
      return None
    }
    bindings.push(
      @lib.InputBinding::new(drop_option_prefix(args[i]), args[i + 1]),
    )
    i = i + 2
  }
  Some(bindings)
}

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

///|
fn run(args : Array[String]) -> @lib.CommandResult {
  let (format, rest) = extract_format(args)
  if rest.is_empty() {
    return Ok(root_help())
  }
  match rest[0] {
    "list" => {
      guard rest.length() == 1 else { return Err("usage: fc list") }
      @lib.run_list()
    }
    "show" => {
      guard rest.length() == 2 else { return Err("usage: fc show ") }
      @lib.run_show(rest[1])
    }
    "calc" => {
      guard rest.length() >= 2 else {
        return Err("usage: fc calc  --  [...]")
      }
      match calc_bindings(rest, 2) {
        Some(bindings) => @lib.run_calc(rest[1], bindings, format~)
        None => Err("usage: fc calc  --  [...]")
      }
    }
    "--help" | "-h" => Ok(root_help())
    command => Err("unknown command `\{command}`")
  }
}

///|
fn main {
  print_result(run(args_without_program()))
}