///|
fn command_parse(args : Array[String]) -> Unit {
  match @problem.parse_problem_json(input_value(args)) {
    Err(error) => print_problem_error(error)
    Ok(result) =>
      println(
        "{\"ok\":true,\"problem\":\{@problem.serialize_problem(result.problem())},\"diagnostics\":\{result.diagnostics().length()}}",
      )
  }
}

///|
fn command_canonicalize(args : Array[String]) -> Unit {
  match @problem.canonicalize_problem_json(input_value(args)) {
    Ok(value) => println(value)
    Err(error) => print_problem_error(error)
  }
}

///|
fn command_validate(args : Array[String]) -> Unit {
  match @problem.parse_problem(input_value(args)) {
    Err(error) => print_problem_error(error)
    Ok(problem) => {
      let semantic = @problem.validate_problem(problem)
      let actual = match option_value(args, "--status") {
        Some(value) => parse_int_text(value)
        None => None
      }
      let context = @problem.problem_context(
        actual,
        option_value(args, "--content-type"),
        option_value(args, "--base-uri"),
      )
      let contextual = @problem.validate_context(problem, context)
      println(
        "{\"ok\":\{semantic.is_empty() && contextual.is_empty()},\"semantic_issues\":\{semantic.length()},\"context_issues\":\{contextual.length()}}",
      )
    }
  }
}

///|
fn command_make(args : Array[String]) -> Unit {
  let builder = @problem.ProblemBuilder::new()
  match option_value(args, "--status") {
    Some(value) =>
      match parse_int_text(value) {
        Some(code) => ignore(builder.status(code))
        None => ()
      }
    None => ()
  }
  match option_value(args, "--title") {
    Some(value) => ignore(builder.title(value))
    None => ()
  }
  match option_value(args, "--type") {
    Some(value) => ignore(builder.type_uri(value))
    None => ()
  }
  match option_value(args, "--detail") {
    Some(value) => ignore(builder.detail(value))
    None => ()
  }
  match option_value(args, "--instance") {
    Some(value) => ignore(builder.instance(value))
    None => ()
  }
  match builder.build() {
    Ok(problem) => println(@problem.serialize_problem(problem))
    Err(error) => print_problem_error(error)
  }
}

///|
fn command_registry(args : Array[String]) -> Unit {
  match positional(args) {
    None =>
      println(
        "{\"count\":\{@problem.registered_problem_types().length()},\"sha256\":\{q(@problem.registry_snapshot_sha256())}}",
      )
    Some(uri) =>
      match @problem.lookup_problem_type(uri) {
        None => println("{\"registered\":false,\"type_uri\":\{q(uri)}}")
        Some(record) =>
          println(
            "{\"registered\":true,\"type_uri\":\{q(record.type_uri())},\"title\":\{q(record.title())},\"reference\":\{q(record.reference())}}",
          )
      }
  }
}

///|
fn command_audit(args : Array[String]) -> Unit {
  match @problem.parse_problem(input_value(args)) {
    Err(error) => print_problem_error(error)
    Ok(problem) => {
      let report = @problem.audit_problem(problem)
      println("{\"ok\":true,\"issues\":\{report.issues().length()}}")
    }
  }
}

///|
fn command_stats(args : Array[String]) -> Unit {
  match @problem.parse_problem_json(input_value(args)) {
    Err(error) => print_problem_error(error)
    Ok(result) => {
      let problem = result.problem()
      println(
        "{\"members\":\{problem.member_count()},\"extensions\":\{problem.extensions().length()},\"diagnostics\":\{result.diagnostics().length()}}",
      )
    }
  }
}

///|
fn command_batch(args : Array[String]) -> Unit {
  let inputs = option_values(args, "--input")
  if inputs.is_empty() {
    print_cli_error(
      "MissingInput", "batch requires one or more repeated --input  options",
    )
    return
  }
  let policy = if has_flag(args, "--strict") {
    @problem.ProblemBatchPolicy::strict()
  } else if has_flag(args, "--permissive") {
    @problem.ProblemBatchPolicy::permissive()
  } else {
    @problem.ProblemBatchPolicy::default()
  }
  println(@problem.analyze_problem_batch(inputs, policy~).summary_json())
}