///|
/// A stable key/value row for human-readable metric exports.
pub(all) struct MetricRow {
  key : String
  value : String
  unit : String
} derive(FromJson, ToJson, Debug, Eq)

///|
/// Convert core time-domain metrics into a stable table.
pub fn metrics_rows(metrics : HrvMetrics) -> Array[MetricRow] {
  [
    { key: "mean_rr", value: metrics.mean_rr.to_string(), unit: "ms" },
    { key: "mean_hr", value: metrics.mean_hr.to_string(), unit: "bpm" },
    { key: "sdnn", value: metrics.sdnn.to_string(), unit: "ms" },
    { key: "rmssd", value: metrics.rmssd.to_string(), unit: "ms" },
    { key: "pnn50", value: metrics.pnn50.to_string(), unit: "%" },
    { key: "pnn_custom", value: metrics.pnn_custom.to_string(), unit: "%" },
    {
      key: "total_beats",
      value: metrics.quality.total_beats.to_string(),
      unit: "beats",
    },
    {
      key: "valid_beats",
      value: metrics.quality.valid_beats.to_string(),
      unit: "beats",
    },
    {
      key: "ectopic_beats",
      value: metrics.quality.ectopic_beats.to_string(),
      unit: "beats",
    },
    {
      key: "clean_ratio",
      value: metrics.quality.clean_ratio.to_string(),
      unit: "ratio",
    },
  ]
}

///|
/// Export a diagnostic as CSV.
pub fn diagnostic_csv(diagnostic : SignalDiagnostic) -> String {
  to_csv([
    ["metric", "value"],
    ["sample_count", diagnostic.sample_count.to_string()],
    ["duration_seconds", diagnostic.duration_seconds.to_string()],
    ["valid_ratio", diagnostic.valid_ratio.to_string()],
    ["artifact_ratio", diagnostic.artifact_ratio.to_string()],
    ["mean_rr", diagnostic.mean_rr.to_string()],
    ["median_rr", diagnostic.median_rr.to_string()],
    ["mean_hr", diagnostic.mean_hr.to_string()],
    ["hr_range", diagnostic.hr_range.to_string()],
    ["rmssd", diagnostic.rmssd.to_string()],
    ["sdnn", diagnostic.sdnn.to_string()],
    ["drift_slope", diagnostic.drift_slope.to_string()],
    ["gap_candidates", diagnostic.gap_candidates.to_string()],
    ["grade", diagnostic.grade],
  ])
}

///|
/// Export a full report's headline metrics as CSV.
pub fn report_headline_csv(report : AnalysisReport) -> String {
  to_csv([
    ["metric", "value", "unit"],
    ["raw_count", report.raw_count.to_string(), "beats"],
    ["clean_count", report.cleaned_intervals.length().to_string(), "beats"],
    ["mean_rr", report.metrics.mean_rr.to_string(), "ms"],
    ["mean_hr", report.metrics.mean_hr.to_string(), "bpm"],
    ["sdnn", report.metrics.sdnn.to_string(), "ms"],
    ["rmssd", report.metrics.rmssd.to_string(), "ms"],
    ["poincare_sd1", report.poincare.sd1.to_string(), "ms"],
    ["poincare_sd2", report.poincare.sd2.to_string(), "ms"],
    ["lf_hf_ratio", report.frequency.lf_hf_ratio.to_string(), "ratio"],
    ["sample_entropy", report.nonlinear.sample_entropy.to_string(), "nats"],
    ["quality_grade", quality_grade(report.raw_validation), ""],
  ])
}

///|
/// Format the report for a compact terminal summary.
pub fn report_summary(report : AnalysisReport) -> String {
  "HRV report: \{report.raw_count} raw beats, \{report.cleaned_intervals.length()} cleaned; mean HR \{report.metrics.mean_hr.to_string()} bpm; RMSSD \{report.metrics.rmssd.to_string()} ms; quality \{quality_grade(report.raw_validation)}"
}