///|
pub fn execute(request : Json) -> Json {
  run(from_json(request)).to_json()
}

///|
pub fn run(request : Value) -> Value {
  try {
    validate_api_fields(request)
    let history = parse_history_value(request)
    let limits = search_limits(request)
    let operation = if has(request, "operation") {
      string(field(request, "operation"))
    } else {
      "check"
    }
    let partitioned = if has(request, "partition") {
      match field(request, "partition") {
        Bool(b) => b
        _ => raise HistoryError("partition must be boolean")
      }
    } else {
      false
    }
    let partitionable = history.model == KeyValue ||
      history.model == Mapping ||
      history.model == LwwMap
    if partitioned && (!partitionable || operation != "check") {
      raise HistoryError(
        "partition requires check on kv_register, map or lww_map",
      )
    }
    match operation {
      "check" =>
        if partitioned {
          check_partitioned(history, limits)
        } else {
          check_verified(history, limits)
        }
      "verify" =>
        verify_history(history, witness_ids(required(request, "witness")))
      "analyze" => analyze_history(history)
      "certify" => certify_history(history, limits)
      "verify_certificate" =>
        verify_certificate(history, required(request, "certificate"))
      "reduce" =>
        reduce_history(history, limits, limit(request, "max_checks", 200, 2000))
      _ => raise HistoryError("unsupported API operation: " + operation)
    }
  } catch {
    HistoryError(message) =>
      record([("verdict", String("invalid_input")), ("reason", String(message))])
  }
}

///|
fn validate_api_fields(request : Value) -> Unit raise HistoryError {
  let operation = if has(request, "operation") {
    string(field(request, "operation"))
  } else {
    "check"
  }
  let allowed = ["operation", "model", "initial", "operations"]
  match operation {
    "check" => {
      allowed.push("partition")
      allowed.push("max_states")
      allowed.push("max_memo_entries")
      allowed.push("max_memo_units")
    }
    "reduce" | "certify" => {
      if operation == "reduce" {
        allowed.push("max_checks")
      }
      allowed.push("max_states")
      allowed.push("max_memo_entries")
      allowed.push("max_memo_units")
    }
    "verify" => allowed.push("witness")
    "verify_certificate" => allowed.push("certificate")
    "analyze" => ()
    _ => raise HistoryError("unsupported API operation: " + operation)
  }
  allowed.push("max_operations")
  fields_only(request, allowed)
}