///|
let demo_document =
  #|# TYPE http_requests counter
  #|# HELP http_requests processed HTTP requests
  #|http_requests_total{method="GET",code="200"} 42 # {trace_id="4bf92f"} 1
  #|# TYPE request_duration_seconds histogram
  #|# UNIT request_duration_seconds seconds
  #|# HELP request_duration_seconds request duration
  #|request_duration_seconds_bucket{le="0.1"} 3
  #|request_duration_seconds_bucket{le="0.5"} 8
  #|request_duration_seconds_bucket{le="+Inf"} 10
  #|request_duration_seconds_sum 2.75
  #|request_duration_seconds_count 10
  #|# EOF
  #|

///|
fn print_usage() -> Unit {
  println(
    (
      #|moonopenmetrics demo
      #|
      #|Usage:
      #|  moon run cmd/main
      #|  moon run cmd/main -- demo
      #|  moon run cmd/main -- validate ""
      #|  moon run cmd/main -- normalize ""
      #|
      #|When no text argument is supplied, validate/normalize use the bundled
      #|demonstration document.
    ),
  )
}

///|
fn input_from_args(args : Array[String]) -> String {
  if args.length() >= 3 {
    args[2]
  } else {
    demo_document
  }
}

///|
fn print_issue(issue : @moonopenmetrics.ValidationIssue) -> Unit {
  let severity = match issue.severity {
    Error => "error"
    Warning => "warning"
  }
  let family = if issue.family == "" { "" } else { issue.family }
  let sample = match issue.sample {
    Some(name) => " sample=\{name}"
    None => ""
  }
  println(
    "\{severity} [\{issue.code}] family=\{family}\{sample}: \{issue.message}",
  )
}

///|
fn parse_or_abort(input : String) -> @moonopenmetrics.Document {
  match @moonopenmetrics.parse(input) {
    Ok(document) => document
    Err(error) => abort("OpenMetrics syntax error: \{error.to_string()}")
  }
}

///|
fn validate_command(input : String) -> Unit {
  let document = parse_or_abort(input)
  let report = @moonopenmetrics.validate(document)
  for issue in report.issues {
    print_issue(issue)
  }
  println(
    "families=\{document.families.length()} errors=\{report.error_count} warnings=\{report.warning_count}",
  )
  println(@moonopenmetrics.summarize(document).to_text())
  if report.error_count > 0 {
    abort("OpenMetrics validation failed")
  }
}

///|
fn normalize_command(input : String) -> Unit {
  let document = parse_or_abort(input)
  println(@moonopenmetrics.encode(document))
}

///|
fn demo_command() -> Unit {
  println("== semantic validation ==")
  validate_command(demo_document)
  println("== canonical exposition ==")
  normalize_command(demo_document)
}

///|
fn main {
  let args = @env.args()
  let command = if args.length() >= 2 { args[1] } else { "demo" }
  match command {
    "demo" => demo_command()
    "validate" => validate_command(input_from_args(args))
    "normalize" => normalize_command(input_from_args(args))
    "help" | "--help" | "-h" => print_usage()
    other => {
      print_usage()
      abort("unknown command '\{other}'")
    }
  }
}