///|
pub fn render_measurement_json(measurement : Measurement) -> String {
  "{\"name\":\"" +
  measurement.name +
  "\",\"value\":" +
  measurement.value.to_string() +
  ",\"unit\":\"" +
  measurement.unit +
  "\",\"decision\":\"" +
  decision_name(measurement.decision) +
  "\",\"deviation\":" +
  measurement.deviation.to_string() +
  "}"
}

///|
pub fn render_batch_json(batch : BatchRun) -> String {
  let out = StringBuilder()
  out.write_string("{\"id\":\"")
  out.write_string(batch.id)
  out.write_string("\",\"measurements\":[")
  for i in 0.. 0 {
      out.write_string(",")
    }
    out.write_string(render_measurement_json(batch.records[i]))
  }
  out.write_string("]}")
  out.to_string()
}

///|
pub fn render_component_json(component : Component) -> String {
  "{\"label\":" +
  component.label.to_string() +
  ",\"area\":" +
  component.area.to_string() +
  ",\"perimeter\":" +
  component.perimeter.to_string() +
  ",\"centroid\":[" +
  component.centroid.x.to_string() +
  "," +
  component.centroid.y.to_string() +
  "]}"
}

///|
pub fn render_components_json(components : Array[Component]) -> String {
  let out = StringBuilder()
  out.write_string("[")
  for i in 0.. 0 {
      out.write_string(",")
    }
    out.write_string(render_component_json(components[i]))
  }
  out.write_string("]")
  out.to_string()
}

///|
pub fn report_status_line(measurements : Array[Measurement]) -> String {
  let counts = decision_counts(measurements)
  "PASS=" +
  counts[0].to_string() +
  " WARN=" +
  counts[1].to_string() +
  " FAIL=" +
  counts[2].to_string()
}

///|
pub fn report_header(title : String, part_id : String) -> String {
  "# " + title + "\n\nPart: " + part_id + "\n\n"
}

///|
pub fn report_footer(toolchain : String) -> String {
  "\n---\nGenerated by moonbit-visual-caliper using " + toolchain + ".\n"
}

///|
pub fn render_full_report(
  part_id : String,
  image : GrayImage,
  result : PipelineResult,
  toolchain : String,
) -> String {
  report_header("Visual Inspection Report", part_id) +
  inspection_markdown(part_id, image, result) +
  "\n" +
  report_status_line(result.measurements) +
  report_footer(toolchain)
}

///|
pub fn render_summary_csv(summary : MeasurementSummary) -> String {
  "total,pass,warn,fail,acceptance_rate,mean,stddev,min,max\n" +
  summary.total.to_string() +
  "," +
  summary.pass.to_string() +
  "," +
  summary.warn.to_string() +
  "," +
  summary.fail.to_string() +
  "," +
  summary.acceptance_rate.to_string() +
  "," +
  summary.values.mean.to_string() +
  "," +
  summary.values.standard_deviation.to_string() +
  "," +
  summary.values.minimum.to_string() +
  "," +
  summary.values.maximum.to_string() +
  "\n"
}

///|
pub fn render_summary_json(summary : MeasurementSummary) -> String {
  "{\"total\":" +
  summary.total.to_string() +
  ",\"pass\":" +
  summary.pass.to_string() +
  ",\"warn\":" +
  summary.warn.to_string() +
  ",\"fail\":" +
  summary.fail.to_string() +
  ",\"acceptance_rate\":" +
  summary.acceptance_rate.to_string() +
  "}"
}

///|
pub fn report_contains_failures(text : String) -> Bool {
  text.contains("FAIL") || text.contains("REJECT")
}

///|
pub fn report_line_count(text : String) -> Int {
  text.split("\n").count()
}

///|
pub fn report_measurement_names(text : String) -> Array[String] {
  let result : Array[String] = []
  for line in text.split("\n") {
    if line.contains("|") && !line.contains("---") && !line.contains("Item") {
      result.push(line.to_owned())
    }
  }
  result
}

///|
pub fn report_is_well_formed(text : String) -> Bool {
  text.contains("#") && text.contains("Decision") && text.contains("Value")
}

///|
pub fn render_profile_csv(profile : ProfileSummary) -> String {
  let out = StringBuilder()
  out.write_string("x,y,value,gradient\n")
  for sample in profile.samples {
    out.write_string(sample.point.x.to_string())
    out.write_string(",")
    out.write_string(sample.point.y.to_string())
    out.write_string(",")
    out.write_string(sample.value.to_string())
    out.write_string(",")
    out.write_string(sample.gradient.to_string())
    out.write_string("\n")
  }
  out.to_string()
}

///|
pub fn render_edges_csv(edges : Array[EdgePoint]) -> String {
  let out = StringBuilder()
  out.write_string("x,y,strength,polarity\n")
  for edge in edges {
    out.write_string(edge.point.x.to_string())
    out.write_string(",")
    out.write_string(edge.point.y.to_string())
    out.write_string(",")
    out.write_string(edge.strength.to_string())
    out.write_string(",")
    out.write_string(edge.polarity.to_string())
    out.write_string("\n")
  }
  out.to_string()
}