///|
pub fn render_batch_text(report : BatchReport) -> String {
  let lines = [
    "ICD batch validation",
    "total: " + report.summary.total.to_string(),
    "valid: " + report.summary.valid.to_string(),
    "unknown: " + report.summary.unknown.to_string(),
    "invalid: " + report.summary.invalid.to_string(),
    "",
  ]
  for item in report.items {
    let normalized = item.report.normalized.unwrap_or("")
    lines.push(
      item.line.to_string() +
      ". " +
      item.input +
      " -> " +
      status_text(item.report.status) +
      " (" +
      normalized +
      ")",
    )
  }
  lines.join("\n")
}

///|
pub fn render_batch_tsv(report : BatchReport) -> String {
  let lines = ["line\tinput\tstatus\tnormalized\tchapter\tissues"]
  for item in report.items {
    let chapter = item.report.chapter.map(fn(value) { value.id }).unwrap_or("")
    let issues = item.report.issues.map(fn(issue) { issue.message }).join(" | ")
    lines.push(
      [
        item.line.to_string(),
        tsv_escape(item.input),
        status_text(item.report.status),
        tsv_escape(item.report.normalized.unwrap_or("")),
        chapter,
        tsv_escape(issues),
      ].join("\t"),
    )
  }
  lines.join("\n") + "\n"
}

///|
pub fn render_batch_json(report : BatchReport) -> String {
  let items = report.items
    .map(fn(item) {
      let normalized = json_escape(item.report.normalized.unwrap_or(""))
      "{\"line\":" +
      item.line.to_string() +
      ",\"input\":\"" +
      json_escape(item.input) +
      "\",\"status\":\"" +
      status_text(item.report.status) +
      "\",\"normalized\":\"" +
      normalized +
      "\"}"
    })
    .join(",")
  "{\"summary\":{\"total\":" +
  report.summary.total.to_string() +
  ",\"valid\":" +
  report.summary.valid.to_string() +
  ",\"unknown\":" +
  report.summary.unknown.to_string() +
  ",\"invalid\":" +
  report.summary.invalid.to_string() +
  "},\"items\":[" +
  items +
  "]}"
}

///|
fn status_text(status : ValidationStatus) -> String {
  match status {
    Valid => "valid"
    Unknown => "unknown"
    Invalid => "invalid"
  }
}

///|
fn json_escape(value : String) -> String {
  value
  .replace_all(old="\\", new="\\\\")
  .replace_all(old="\"", new="\\\"")
  .replace_all(old="\n", new="\\n")
  .replace_all(old="\r", new="\\r")
}

///|
fn tsv_escape(value : String) -> String {
  value
  .replace_all(old="\t", new=" ")
  .replace_all(old="\n", new=" ")
  .replace_all(old="\r", new=" ")
}