///|
/// Human-readable quality report sections.
pub(all) struct ReportSection {
  title : String
  lines : Array[String]
} derive(Debug, ToJson)

///|
/// A report document composed from deterministic sections.
pub(all) struct ReportDocument {
  title : String
  generated_at : String
  sections : Array[ReportSection]
  warnings : Array[String]
} derive(Debug, ToJson)

///|
/// Create an empty report document.
pub fn ReportDocument::new(
  title~ : String,
  generated_at~ : String,
) -> ReportDocument {
  { title, generated_at, sections: [], warnings: [] }
}

///|
/// Append a section while preserving insertion order.
pub fn ReportDocument::add_section(
  self : ReportDocument,
  title~ : String,
  lines~ : Array[String],
) -> Unit {
  self.sections.push({ title, lines })
}

///|
/// Append an audit warning.
pub fn ReportDocument::warn(self : ReportDocument, message : String) -> Unit {
  self.warnings.push(message)
}

///|
/// Render a document as Markdown.
pub fn ReportDocument::to_markdown(self : ReportDocument) -> String {
  let builder = StringBuilder()
  builder.write_string("# ")
  builder.write_string(self.title)
  builder.write_string("\n\n")
  builder.write_string("Generated: ")
  builder.write_string(self.generated_at)
  builder.write_string("\n\n")
  for section in self.sections {
    builder.write_string("## ")
    builder.write_string(section.title)
    builder.write_string("\n\n")
    for line in section.lines {
      builder.write_string("- ")
      builder.write_string(line)
      builder.write_string("\n")
    }
    builder.write_string("\n")
  }
  if self.warnings.length() > 0 {
    builder.write_string("## Warnings\n\n")
    for warning in self.warnings {
      builder.write_string("- ")
      builder.write_string(warning)
      builder.write_string("\n")
    }
  }
  builder.to_string()
}

///|
/// Build a summary section from one statistical summary.
pub fn summary_section(summary : Summary) -> ReportSection {
  {
    title: "Summary",
    lines: [
      "count=\{summary.count}",
      "mean=\{summary.mean}",
      "standard_deviation=\{summary.standard_deviation}",
      "minimum=\{summary.minimum}",
      "maximum=\{summary.maximum}",
      "out_of_spec_rate=\{summary.out_of_spec_rate}",
      "batch=\{summary.batch}",
      "equipment=\{summary.equipment}",
      "tool=\{summary.tool}",
      "operator=\{summary.operator}",
      "window=\{summary.window}",
    ],
  }
}

///|
/// Build a capability section.
pub fn capability_section(capability : Capability) -> ReportSection {
  {
    title: "Capability",
    lines: [
      "mean=\{capability.mean}",
      "standard_deviation=\{capability.standard_deviation}",
      "cp=\{capability.cp}",
      "cpk=\{capability.cpk}",
      "pp=\{capability.pp}",
      "ppk=\{capability.ppk}",
      "out_of_spec_rate=\{capability.out_of_spec_rate}",
    ],
  }
}

///|
/// Build a chart section.
pub fn chart_section(chart : ControlChart) -> ReportSection {
  let lines : Array[String] = [
    "kind=\{chart.kind}",
    "center=\{chart.center}",
    "points=\{chart.points.length()}",
  ]
  for point in chart.points {
    lines.push(
      "value=\{point.value}, lower=\{point.lower}, upper=\{point.upper}, alarm=\{point.out_of_control}",
    )
  }
  { title: "Control chart", lines }
}

///|
/// Build a violation section.
pub fn violation_section(violations : Array[RuleViolation]) -> ReportSection {
  let lines : Array[String] = []
  for violation in violations {
    lines.push(
      "rule=\{violation.rule}, start=\{violation.start_index}, indices=\{Repr(violation.indices)}, message=\{violation.message}",
    )
  }
  { title: "Rule violations", lines }
}

///|
/// Build a quality document from a report result.
pub fn document_quality_report(
  result : ReportResult,
  generated_at : String,
) -> ReportDocument {
  let document = ReportDocument::new(title="Quality report", generated_at~)
  match result {
    ReportOk(report) => {
      let summary = summary_section(report.summary)
      document.add_section(title=summary.title, lines=summary.lines)
      match report.capability {
        Some(capability) => {
          let section = capability_section(capability)
          document.add_section(title=section.title, lines=section.lines)
        }
        None => document.warn("capability indices were not available")
      }
      match report.chart {
        Some(chart) => {
          let section = chart_section(chart)
          document.add_section(title=section.title, lines=section.lines)
        }
        None => ()
      }
      let section = violation_section(report.violations)
      document.add_section(title=section.title, lines=section.lines)
    }
    ReportInvalidInput(message~) => document.warn(message)
  }
  document
}

///|
/// Render a scorecard as a compact Markdown table.
pub fn scorecard_markdown(card : Scorecard) -> String {
  "| Metric | Value |\n|---|---|\n| observations | \{card.observations} |\n| windows | \{card.windows} |\n| alerts | \{card.alerts} |\n| critical | \{card.critical} |\n| defect_rate | \{Repr(card.defect_rate)} |\n| center | \{Repr(card.center)} |\n| deviation | \{Repr(card.deviation)} |\n"
}

///|
/// Render an alert list as JSON-compatible text without external dependencies.
pub fn alerts_text(alerts : Array[QualityAlert]) -> String {
  let builder = StringBuilder()
  builder.write_string("[")
  for index, alert in alerts {
    if index > 0 {
      builder.write_string(",")
    }
    builder.write_string("{code:\"")
    builder.write_string(alert.code)
    builder.write_string("\",message:\"")
    builder.write_string(alert.message)
    builder.write_string("\"}")
  }
  builder.write_string("]")
  builder.to_string()
}

///|
/// Add pipeline alerts to an existing document.
pub fn add_alert_section(
  document : ReportDocument,
  alerts : Array[QualityAlert],
) -> Unit {
  let lines : Array[String] = []
  for alert in alerts {
    lines.push(
      "code=\{alert.code}, message=\{alert.message}, index=\{alert.index}",
    )
  }
  document.add_section(title="Alerts", lines~)
}

///|
/// Add benchmark observations to a report.
pub fn add_benchmark_section(
  document : ReportDocument,
  sample_count : Int,
  elapsed_ms : Double,
) -> Unit {
  document.add_section(title="Benchmark", lines=[
    "sample_count=\{sample_count}",
    "elapsed_ms=\{elapsed_ms}",
  ])
}

///|
/// Add a provenance section.
pub fn add_provenance_section(
  document : ReportDocument,
  source : String,
  version : String,
) -> Unit {
  document.add_section(title="Provenance", lines=[
    "source=\{source}",
    "version=\{version}",
  ])
}

///|
/// Count report warnings.
pub fn report_warning_count(document : ReportDocument) -> Int {
  document.warnings.length()
}

///|
/// Count report sections.
pub fn report_section_count(document : ReportDocument) -> Int {
  document.sections.length()
}

///|
/// Return whether a document has no warnings.
pub fn report_is_clean(document : ReportDocument) -> Bool {
  document.warnings.length() == 0
}

///|
/// Return titles for all sections.
pub fn report_section_titles(document : ReportDocument) -> Array[String] {
  let result : Array[String] = []
  for section in document.sections {
    result.push(section.title)
  }
  result
}