///|
/// Builds a compact human-readable audit report.
pub fn AuditReport::text_report(self : AuditReport) -> String {
  let mut output = "MoonCIDR Audit report\n"
  output = output + "rules: " + self.rules.length().to_string() + "\n"
  output = output + "findings: " + self.finding_count().to_string() + "\n"
  output = output +
    "risk: " +
    self.risk_level() +
    " (score=" +
    self.risk_score().to_string() +
    ")\n"
  output = output + "recommendation: " + self.recommended_action() + "\n"
  if self.findings.length() == 0 {
    output + "\nNo findings."
  } else {
    output = output + "\nFindings:\n"
    for finding in self.findings {
      output = output +
        "- [" +
        finding.severity().label() +
        "] " +
        finding.kind().label()
      if finding.rule_id() != "" {
        output = output + " " + finding.rule_id()
      }
      if finding.related_rule_id() != "" {
        output = output + " related=" + finding.related_rule_id()
      }
      output = output + ": " + finding.message() + "\n"
    }
    output
  }
}

///|
/// Builds a stable JSON-like report without external dependencies.
pub fn AuditReport::json_report(self : AuditReport) -> String {
  let mut output = "{"
  output = output + "\"rules\":" + self.rules.length().to_string() + ","
  output = output + "\"findings\":" + self.finding_count().to_string() + ","
  output = output + "\"risk_level\":\"" + escape_json(self.risk_level()) + "\","
  output = output + "\"risk_score\":" + self.risk_score().to_string() + ","
  output = output +
    "\"recommended_action\":\"" +
    escape_json(self.recommended_action()) +
    "\","
  output = output + "\"items\":["
  for index = 0; index < self.findings.length(); index = index + 1 {
    let finding = self.findings[index]
    if index > 0 {
      output = output + ","
    }
    output = output + "{"
    output = output +
      "\"kind\":\"" +
      escape_json(finding.kind().label()) +
      "\","
    output = output +
      "\"severity\":\"" +
      escape_json(finding.severity().label()) +
      "\","
    output = output + "\"rule\":\"" + escape_json(finding.rule_id()) + "\","
    output = output +
      "\"related\":\"" +
      escape_json(finding.related_rule_id()) +
      "\","
    output = output + "\"message\":\"" + escape_json(finding.message()) + "\""
    output = output + "}"
  }
  output + "]}"
}

///|
pub fn AuditReport::summary_table(self : AuditReport) -> String {
  let mut output = "kind | severity | rule | related | message\n"
  output = output + "--- | --- | --- | --- | ---\n"
  for finding in self.findings {
    output = output +
      finding.kind().label() +
      " | " +
      finding.severity().label() +
      " | " +
      finding.rule_id() +
      " | " +
      finding.related_rule_id() +
      " | " +
      finding.message() +
      "\n"
  }
  output
}

///|
fn escape_json(input : String) -> String {
  let chars = input.to_array()
  let output : Array[Char] = []
  for char in chars {
    if char == '"' {
      output.push('\\')
      output.push('"')
    } else if char == '\\' {
      output.push('\\')
      output.push('\\')
    } else if char == '\n' {
      output.push('\\')
      output.push('n')
    } else if char == '\r' {
      output.push('\\')
      output.push('r')
    } else if char == '\t' {
      output.push('\\')
      output.push('t')
    } else {
      output.push(char)
    }
  }
  String::from_array(output)
}