///| Dependency-free JSON rendering for metadata that has already been parsed.

///| Strings are escaped here rather than delegated to callers, making reports

///|
/// safe to consume in CI artifacts and editor integrations.
fn json_escape(value : String) -> String {
  let mut text = ""
  for char in value {
    match char {
      '"' => text = text + "\\\""
      '\\' => text = text + "\\\\"
      '\n' => text = text + "\\n"
      '\r' => text = text + "\\r"
      '\t' => text = text + "\\t"
      _ => text = text + char.to_string()
    }
  }
  text
}

///|
fn json_string(value : String) -> String {
  "\"" + json_escape(value) + "\""
}

///|
fn json_array(values : Array[String]) -> String {
  let mut text = "["
  let mut first = true
  for value in values {
    if !first {
      text = text + ","
    }
    text = text + value
    first = false
  }
  text + "]"
}

///|
pub fn render_structure_json(binary : Module) -> String {
  let sections : Array[String] = []
  for section in binary.sections() {
    let custom = match section.custom_name {
      Some(name) => ",\"name\":" + json_string(name)
      None => ""
    }
    sections.push(
      "{\"id\":" +
      section.id.to_string() +
      ",\"kind\":" +
      json_string(section.kind.label()) +
      ",\"start\":" +
      section.payload.start.to_string() +
      ",\"end\":" +
      section.payload.end.to_string() +
      custom +
      "}",
    )
  }
  "{\"version\":" +
  binary.version().to_string() +
  ",\"bytes\":" +
  binary.byte_length().to_string() +
  ",\"sections\":" +
  json_array(sections) +
  "}"
}

///|
pub fn render_validation_json(report : ValidationReport) -> String {
  let values : Array[String] = []
  for issue in report.issues() {
    values.push(
      "{\"level\":" +
      json_string(issue.level.label()) +
      ",\"rule\":" +
      json_string(issue.rule) +
      ",\"message\":" +
      json_string(issue.message) +
      "}",
    )
  }
  "{\"ok\":" +
  (!report.has_errors()).to_string() +
  ",\"issues\":" +
  json_array(values) +
  "}"
}