///|
pub struct AuditRecord {
  sequence : Int
  event_id : String
  provider : String
  status : String
  risk_level : String
  route_handler : String
  digest : String
} derive(Eq, Debug)

///|
pub fn AuditRecord::new(
  sequence : Int,
  event_id : String,
  provider : String,
  status : String,
  risk_level : String,
  route_handler : String,
  digest : String,
) -> AuditRecord {
  { sequence, event_id, provider, status, risk_level, route_handler, digest }
}

///|
pub fn audit_digest(previous : String, output : GuardPipelineOutput) -> String {
  stable_sign(
    "audit",
    previous +
    "\n" +
    output.verification.provider +
    "\n" +
    output.verification.event_id +
    "\n" +
    output.risk.level,
  ).value
}

///|
pub fn audit_record(
  sequence : Int,
  previous_digest : String,
  output : GuardPipelineOutput,
) -> AuditRecord {
  let status = if output.verification.is_ok() { "accepted" } else { "rejected" }
  let handler = if output.route.matched { output.route.handler } else { "" }
  AuditRecord::new(
    sequence,
    output.verification.event_id,
    output.verification.provider,
    status,
    output.risk.level,
    handler,
    audit_digest(previous_digest, output),
  )
}

///|
pub fn build_audit_log(
  outputs : Array[GuardPipelineOutput],
) -> Array[AuditRecord] {
  let mut previous = "root"
  Array::makei(outputs.length(), i => {
    let record = audit_record(i, previous, outputs[i])
    previous = record.digest
    record
  })
}

///|
pub fn audit_log_markdown(records : Array[AuditRecord]) -> String {
  let builder = StringBuilder::new()
  builder.write_string(
    "| seq | provider | event_id | status | risk | handler | digest |\n",
  )
  builder.write_string("| ---: | --- | --- | --- | --- | --- | --- |\n")
  for i in 0.. Bool {
  if records.length() != outputs.length() {
    return false
  }
  let mut previous = "root"
  for i in 0..