///|
pub fn change_name(kind : ChangeKind) -> String {
  match kind {
    NewGrant => "NEW_GRANT"
    RevokedGrant => "REVOKED_GRANT"
    UnchangedAllow => "UNCHANGED_ALLOW"
    UnchangedDeny => "UNCHANGED_DENY"
    Inconclusive => "INCONCLUSIVE"
  }
}

///|
pub fn verdict_name(verdict : GateVerdict) -> String {
  match verdict {
    Pass => "PASS"
    Fail => "FAIL"
    Indeterminate => "INDETERMINATE"
  }
}

///|
pub fn render_report(report : AuditReport, gate : GateResult) -> String {
  let out = StringBuilder()
  out.write_string("MoonPolicyDiff audit\n")
  out.write_string("Before: \{report.before_name}\n")
  out.write_string("After: \{report.after_name}\n")
  out.write_string(
    "Coverage: \{report.requests_considered} explicit requests\n",
  )
  out.write_string("Complete: \{report.complete}\n")
  out.write_string("Gate: \{verdict_name(gate.verdict)}\n")
  out.write_string("New grants: \{count_changes(report, NewGrant)}\n")
  out.write_string("Revocations: \{count_changes(report, RevokedGrant)}\n")
  for diagnostic in report.diagnostics {
    out.write_string("DIAGNOSTIC \{diagnostic.code}: \{diagnostic.message}\n")
  }
  for change in report.changes {
    if change.kind is NewGrant ||
      change.kind is RevokedGrant ||
      change.kind is Inconclusive {
      out.write_string(
        "\{change_name(change.kind)} \{change.request.principal_id} \{change.request.action} \{change.request.resource_id}\n",
      )
      out.write_string("  before: \{change.before.explanation}; rules: ")
      write_ids(out, change.before.decisive_rules)
      out.write_string("\n")
      out.write_string("  after: \{change.after.explanation}; rules: ")
      write_ids(out, change.after.decisive_rules)
      out.write_string("\n")
    }
  }
  for finding in gate.findings {
    out.write_string(
      "FINDING \{finding.code}: \{finding.request.principal_id} \{finding.request.action} \{finding.request.resource_id}\n",
    )
  }
  out.to_string()
}

///|
fn write_ids(out : StringBuilder, ids : Array[String]) -> Unit {
  if ids.length() == 0 {
    out.write_string("(none)")
    return
  }
  for index, id in ids {
    if index > 0 {
      out.write_string(",")
    }
    out.write_string(id)
  }
}