///|
fn sarif_level(severity : Severity) -> String {
  match severity {
    Error => "error"
    Warn => "warning"
    Info => "note"
  }
}

///|
fn sarif_rule(rule : RuleDefinition) -> Json {
  Json::object({
    "id": Json::string(rule.id),
    "name": Json::string(rule.id),
    "shortDescription": Json::object({ "text": Json::string(rule.title) }),
    "fullDescription": Json::object({ "text": Json::string(rule.description) }),
    "help": Json::object({ "text": Json::string(rule.remediation) }),
    "properties": Json::object({
      "category": Json::string(rule.category.label()),
      "defaultSeverity": Json::string(rule.default_severity.label()),
    }),
  })
}

///|
fn sarif_region(location : SourceLocation) -> Json {
  Json::object({
    "startLine": Json::number(location.line.to_double()),
    "startColumn": Json::number(location.column.to_double()),
  })
}

///|
fn sarif_location(location : SourceLocation) -> Json {
  Json::object({
    "physicalLocation": Json::object({
      "artifactLocation": Json::object({ "uri": Json::string(location.path) }),
      "region": sarif_region(location),
    }),
  })
}

///|
fn sarif_fix(diagnostic : Diagnostic) -> Json? {
  if diagnostic.remediation.length() == 0 {
    None
  } else {
    Some(
      Json::object({
        "description": Json::object({
          "text": Json::string(diagnostic.remediation.join(" ")),
        }),
      }),
    )
  }
}

///|
fn sarif_result(diagnostic : Diagnostic) -> Json {
  let locations = match diagnostic.location {
    Some(location) => [sarif_location(location)]
    None => []
  }
  let result : Map[String, Json] = {
    "ruleId": Json::string(diagnostic.code),
    "level": Json::string(sarif_level(diagnostic.severity)),
    "message": Json::object({
      "text": Json::string(diagnostic.message + ": " + diagnostic.detail),
    }),
    "locations": Json::array(locations),
  }
  match sarif_fix(diagnostic) {
    Some(fix) => result["fixes"] = Json::array([fix])
    None => ()
  }
  Json::object(result)
}

///|
fn sarif_driver() -> Json {
  Json::object({
    "name": Json::string("Moon Doctor"),
    "informationUri": Json::string(
      "https://github.com/sheldonshi115/moon-doctor",
    ),
    "rules": Json::array(rule_catalog().map(sarif_rule)),
  })
}

///|
/// Render a deterministic SARIF 2.1.0 document for GitHub Code Scanning.
pub fn render_sarif_report(report : DoctorReport) -> String {
  let document = Json::object({
    "$schema": Json::string("https://json.schemastore.org/sarif-2.1.0.json"),
    "version": Json::string("2.1.0"),
    "runs": Json::array([
      Json::object({
        "tool": Json::object({ "driver": sarif_driver() }),
        "results": Json::array(report.diagnostics.map(sarif_result)),
        "properties": Json::object({
          "project": Json::string(report.root),
          "profile": Json::string(report.profile),
          "conclusion": Json::string(report.conclusion()),
        }),
      }),
    ]),
  })
  document.stringify()
}