///|
/// Result of a CLI command after argument parsing.
pub(all) enum CliResult {
  Ok(String)
  Err(String)
} derive(Eq, Debug)

///|
pub impl Show for CliResult with fn output(self, logger) {
  match self {
    Ok(text) => {
      logger.write_string("Ok(")
      Show::output(text, logger)
      logger.write_string(")")
    }
    Err(text) => {
      logger.write_string("Err(")
      Show::output(text, logger)
      logger.write_string(")")
    }
  }
}

///|
/// Returns the unit formatter style selected by CLI text.
pub fn parse_format_style(style : String) -> @unit.FormatStyle? {
  match style {
    "ascii" => Some(Ascii)
    "si" => Some(Si)
    "latex" => Some(Latex)
    _ => None
  }
}

///|
/// Converts a parsed quantity expression to a target unit expression.
pub fn run_convert(
  quantity_text : String,
  target_unit_text : String,
  format? : String = "ascii",
) -> CliResult {
  guard parse_format_style(format) is Some(style) else {
    return Err("unknown output format: \{format}")
  }
  let catalog = @preset.all()
  let quantity = @parser.parse_quantity(catalog, quantity_text) catch {
    err => return Err("invalid quantity expression `\{quantity_text}`: \{err}")
  }
  let target_unit = @parser.parse_unit(catalog, target_unit_text) catch {
    err => return Err("invalid target unit `\{target_unit_text}`: \{err}")
  }
  let converted = quantity.checked_to(target_unit)
  guard converted is Some(value) else {
    return Err(
      "incompatible dimensions: cannot convert `\{quantity_text}` to `\{target_unit_text}`",
    )
  }
  Ok(@quantity.format_quantity_with(value, style))
}

///|
/// Parses a quantity expression and renders its normalized quantity.
pub fn run_parse(input : String, format? : String = "ascii") -> CliResult {
  guard parse_format_style(format) is Some(style) else {
    return Err("unknown output format: \{format}")
  }
  let catalog = @preset.all()
  let quantity = @parser.parse_quantity(catalog, input) catch {
    err => return Err("invalid quantity expression `\{input}`: \{err}")
  }
  Ok(@quantity.format_quantity_with(quantity, style))
}

///|
/// Parses a unit expression and renders its normalized unit.
pub fn run_parse_unit(input : String, format? : String = "ascii") -> CliResult {
  guard parse_format_style(format) is Some(style) else {
    return Err("unknown output format: \{format}")
  }
  let catalog = @preset.all()
  let unit = @parser.parse_unit(catalog, input) catch {
    err => return Err("invalid unit expression `\{input}`: \{err}")
  }
  Ok(@unit.format_unit_with(unit, style))
}

///|
/// Looks up one unit symbol through the preset catalog.
pub fn run_inspect(symbol : String, format? : String = "ascii") -> CliResult {
  guard parse_format_style(format) is Some(style) else {
    return Err("unknown output format: \{format}")
  }
  let catalog = @preset.all()
  let unit = @parser.parse_unit(catalog, symbol) catch {
    err => return Err("invalid unit expression `\{symbol}`: \{err}")
  }
  Ok(
    "symbol: \{symbol}\nunit: \{@unit.format_unit_with(unit, style)}\ndimension: \{unit.dimension()}",
  )
}