///|
/// Render a compact human-readable audit report.
pub fn render_text(report : AuditReport) -> String {
  let out = StringBuilder::new()
  out.write_string("MoonSeal audit: \{report.project.name}\n")
  out.write_string("Score: \{report.score}/100\n")
  out.write_string(
    "Source: \{report.moonbit_source_lines} MoonBit lines | \{report.error_count()} errors | \{report.warning_count()} warnings\n",
  )
  if report.findings.is_empty() {
    out.write_string("\nREADY  No release-readiness issues found.\n")
  } else {
    out.write_string("\n")
    for finding in report.findings {
      let location = if finding.path.is_empty() {
        ""
      } else {
        " [\{finding.path}]"
      }
      out.write_string(
        "\{finding.severity.label()} \{finding.code}\{location}: \{finding.message}\n",
      )
    }
  }
  out.to_string()
}

///|
fn finding_json(finding : Finding) -> Json {
  {
    "severity": finding.severity.label(),
    "code": finding.code,
    "path": finding.path,
    "message": finding.message,
  }
}

///|
/// Render a machine-readable report suitable for CI.
pub fn render_json(report : AuditReport, indent? : Int = 2) -> String {
  let findings : Array[Json] = report.findings.map(finding_json)
  let value : Json = {
    "tool": { "name": "MoonSeal", "version": "0.2.1" },
    "project": {
      "name": report.project.name,
      "version": report.project.version,
      "license": report.project.license,
      "repository": report.project.repository,
    },
    "summary": {
      "ready": report.is_ready(),
      "score": report.score,
      "errors": report.error_count(),
      "warnings": report.warning_count(),
      "moonbitSourceLines": report.moonbit_source_lines,
    },
    "findings": findings,
  }
  value.stringify(indent~)
}

///|
/// Render an audit report for issue trackers, pull requests, and build
/// summaries.
pub fn render_markdown(report : AuditReport) -> String {
  let out = StringBuilder::new()
  out.write_string("# MoonSeal audit: `\{report.project.name}`\n\n")
  out.write_string(
    "- Status: **\{if report.is_ready() { "READY" } else { "BLOCKED" }}**\n",
  )
  out.write_string("- Score: **\{report.score}/100**\n")
  out.write_string("- MoonBit source lines: \{report.moonbit_source_lines}\n")
  out.write_string(
    "- Findings: \{report.error_count()} errors, \{report.warning_count()} warnings\n",
  )
  if report.findings.is_empty() {
    out.write_string("\nNo release-readiness issues found.\n")
  } else {
    out.write_string("\n| Severity | Code | Path | Finding |\n")
    out.write_string("| --- | --- | --- | --- |\n")
    for finding in report.findings {
      out.write_string(
        "| \{finding.severity.label()} | \{finding.code} | `\{finding.path}` | \{finding.message} |\n",
      )
    }
  }
  out.to_string()
}