///|
fn render_check(request : @lib.CommandRequest) -> Unit raise {
  let config = match request.config_path {
    None =>
      match request.profile {
        None => @lib.load_config(request.target)
        Some(profile) => @lib.load_config(request.target, profile~)
      }
    Some(path) =>
      match request.profile {
        None => @lib.load_config(request.target, path~)
        Some(profile) => @lib.load_config(request.target, path~, profile~)
      }
  }
  let report = @lib.analyze_project(request.target, config)
  match request.format {
    @lib.Text => println(@lib.render_report(report))
    @lib.Json => println(@lib.render_json_report(report))
    @lib.Sarif => println(@lib.render_sarif_report(report))
  }
  if request.strict && (report.score.errors > 0 || report.score.warnings > 0) {
    @abort.abort("Moon Doctor strict mode failed")
  }
}

///|
fn render_rules(request : @lib.CommandRequest) -> Unit {
  match request.format {
    @lib.Text => println(@lib.render_rule_catalog())
    @lib.Json =>
      println(
        Json::array(
          @lib.rule_catalog().map(rule => {
            Json::object({
              "id": Json::string(rule.id),
              "category": Json::string(rule.category.label()),
              "severity": Json::string(rule.default_severity.label()),
              "title": Json::string(rule.title),
            })
          }),
        ).stringify(),
      )
    @lib.Sarif => @abort.abort("rules does not support SARIF output")
  }
}

///|
fn render_explain(rule_id : String, request : @lib.CommandRequest) -> Unit {
  match request.format {
    @lib.Text =>
      match @lib.render_rule_explanation(rule_id) {
        Some(text) => println(text)
        None => @abort.abort("unknown rule: " + rule_id)
      }
    @lib.Json =>
      match @lib.render_rule_explanation_json(rule_id) {
        Some(text) => println(text)
        None => @abort.abort("unknown rule: " + rule_id)
      }
    @lib.Sarif => @abort.abort("explain does not support SARIF output")
  }
}

///|
/// Run Moon Doctor commands. Legacy no-command invocation remains a check.
fn main raise {
  match @lib.parse_command_request(@env.args()) {
    Ok(request) =>
      if request.help {
        println(@lib.command_usage())
      } else {
        match request.command {
          @lib.Check => render_check(request)
          @lib.Rules => render_rules(request)
          @lib.Explain(rule_id) => render_explain(rule_id, request)
        }
      }
    Err(message) => @abort.abort(message + "\n\n" + @lib.command_usage())
  }
}