///|
fn action_name(action : SeccompAction) -> String {
  match action {
    Allow => "allow"
    Errno(errno) => "errno(\{errno})"
    Trap => "trap"
    Log => "log"
    KillProcess => "kill-process"
  }
}

///|
fn architecture_name(architecture : Architecture) -> String {
  match architecture {
    X86_64 => "x86_64"
    AArch64 => "aarch64"
  }
}

///|
/// Render a deterministic, human-readable explanation of a compiled plan.
pub fn SandboxPlan::explain(self : SandboxPlan) -> String {
  let out = StringBuilder()
  out.write_string("MoonJail plan: ")
  out.write_string(self.name)
  out.write_string("\narchitecture: ")
  out.write_string(architecture_name(self.architecture))
  out.write_string("\nseccomp instructions: ")
  out.write_string(self.seccomp.instructions.length().to_string())
  out.write_string("\ndefault action: ")
  out.write_string(action_name(self.default_action))
  out.write_string("\nsyscalls:")
  if self.syscall_rules.is_empty() {
    out.write_string(" none")
  } else {
    for rule in self.syscall_rules {
      out.write_string("\n  - \{rule.name}: \{action_name(rule.action)}")
    }
  }
  out.write_string("\nlandlock: ")
  out.write_string(
    if self.require_landlock || !self.path_rules.is_empty() {
      "required"
    } else {
      "off"
    },
  )
  out.write_string("\npaths:")
  if self.path_rules.is_empty() {
    out.write_string(" none")
  } else {
    for rule in self.path_rules {
      out.write_string("\n  - ")
      out.write_string(rule.path)
      out.write_string(" [")
      out.write_string(rule.rights.map(right => "\{Repr(right)}").join(", "))
      out.write_string("]")
    }
  }
  out.write_string("\nlimits:")
  let mut has_limit = false
  match self.limits.cpu_seconds {
    Some(value) => {
      out.write_string("\n  - cpu_seconds: \{value}")
      has_limit = true
    }
    None => ()
  }
  match self.limits.address_space_bytes {
    Some(value) => {
      out.write_string("\n  - address_space_bytes: \{value}")
      has_limit = true
    }
    None => ()
  }
  match self.limits.file_size_bytes {
    Some(value) => {
      out.write_string("\n  - file_size_bytes: \{value}")
      has_limit = true
    }
    None => ()
  }
  match self.limits.open_files {
    Some(value) => {
      out.write_string("\n  - open_files: \{value}")
      has_limit = true
    }
    None => ()
  }
  match self.limits.processes {
    Some(value) => {
      out.write_string("\n  - processes: \{value}")
      has_limit = true
    }
    None => ()
  }
  if !has_limit {
    out.write_string(" none")
  }
  out.write_string("\n")
  out.to_string()
}

///|
/// Summarize a policy before compilation.
pub fn Policy::summary(self : Policy) -> String {
  let lines : Array[String] = [
    "policy \{self.name}",
    "default: \{action_name(self.default_action)}",
    "syscall rules: \{self.syscall_rules.length()}",
    "path rules: \{self.path_rules.length()}",
  ]
  lines.join("\n")
}