///|
/// Human-readable quality report for one seismic trace.
pub struct WorkflowReport {
  station : String
  channel : String
  source_samples : Int
  processed_samples : Int
  source_duration : Double
  processed_duration : Double
  quality_score : Double
  dominant_frequency : Double
  event_count : Int
  peak_amplitude : Double
  roundtrip_sac : Bool
  roundtrip_miniseed : Bool
}

///|
/// Build a report from the standard analysis pipeline.
pub fn build_workflow_report(
  trace : Trace,
  config : ProcessingConfig,
) -> Result[WorkflowReport, String] {
  let result = match analyze_trace(trace, config) {
    Ok(value) => value
    Err(message) => return Err(message)
  }
  Ok({
    station: trace.station,
    channel: trace.channel,
    source_samples: trace.npts(),
    processed_samples: result.processed.npts(),
    source_duration: trace.duration(),
    processed_duration: result.processed.duration(),
    quality_score: result.quality.score,
    dominant_frequency: result.dominant_frequency,
    event_count: result.events.length(),
    peak_amplitude: peak_amplitude(result.processed),
    roundtrip_sac: validate_sac_roundtrip_size(result.processed),
    roundtrip_miniseed: validate_miniseed_roundtrip_size(result.processed),
  })
}

///|
/// Serialize a report as a stable key-value table for CLI output.
pub fn workflow_report_text(report : WorkflowReport) -> String {
  "station=" +
  report.station +
  "\n" +
  "channel=" +
  report.channel +
  "\n" +
  "source_samples=" +
  report.source_samples.to_string() +
  "\n" +
  "processed_samples=" +
  report.processed_samples.to_string() +
  "\n" +
  "source_duration=" +
  report.source_duration.to_string() +
  "\n" +
  "processed_duration=" +
  report.processed_duration.to_string() +
  "\n" +
  "quality_score=" +
  report.quality_score.to_string() +
  "\n" +
  "dominant_frequency=" +
  report.dominant_frequency.to_string() +
  "\n" +
  "event_count=" +
  report.event_count.to_string() +
  "\n" +
  "peak_amplitude=" +
  report.peak_amplitude.to_string() +
  "\n" +
  "sac_roundtrip=" +
  report.roundtrip_sac.to_string() +
  "\n" +
  "miniseed_roundtrip=" +
  report.roundtrip_miniseed.to_string()
}

///|
/// Return a compact status badge for automation.
pub fn workflow_status(report : WorkflowReport) -> String {
  if report.quality_score >= 0.7 &&
    report.roundtrip_sac &&
    report.roundtrip_miniseed {
    "PASS"
  } else {
    "REVIEW"
  }
}

///|
/// Build and format a report in one call.
pub fn analyze_and_report(trace : Trace) -> Result[String, String] {
  match build_workflow_report(trace, default_processing_config()) {
    Ok(report) =>
      Ok(workflow_status(report) + "\n" + workflow_report_text(report))
    Err(message) => Err(message)
  }
}

///|
/// Return true when both binary format round trips are available.
pub fn report_roundtrips_pass(report : WorkflowReport) -> Bool {
  report.roundtrip_sac && report.roundtrip_miniseed
}

///|
/// Return a one-line report suitable for benchmark logs.
pub fn workflow_report_line(report : WorkflowReport) -> String {
  workflow_status(report) +
  " " +
  report.station +
  "." +
  report.channel +
  " samples=" +
  report.processed_samples.to_string() +
  " quality=" +
  report.quality_score.to_string() +
  " events=" +
  report.event_count.to_string()
}

///|
/// Return a normalized quality score suitable for a dashboard gauge.
pub fn report_quality_percent(report : WorkflowReport) -> Double {
  report.quality_score.max(0.0).min(1.0) * 100.0
}

///|
/// Return the number of source samples removed by processing.
pub fn report_sample_reduction(report : WorkflowReport) -> Int {
  report.source_samples - report.processed_samples
}

///|
/// Return whether the report contains at least one usable event.
pub fn report_has_event(report : WorkflowReport) -> Bool {
  report.event_count > 0 && report.peak_amplitude > 0.0
}

///|
/// Return a machine-readable pass/fail value for CI smoke checks.
pub fn report_passes(report : WorkflowReport) -> Bool {
  workflow_status(report) == "PASS"
}

///|
/// Return the processed duration in milliseconds.
pub fn report_duration_milliseconds(report : WorkflowReport) -> Double {
  report.processed_duration * 1000.0
}

///|
/// Return the report's dominant frequency in millihertz.
pub fn report_dominant_millihertz(report : WorkflowReport) -> Double {
  report.dominant_frequency * 1000.0
}

///|
/// Return the number of boolean round-trip checks that passed.
pub fn report_roundtrip_count(report : WorkflowReport) -> Int {
  (if report.roundtrip_sac { 1 } else { 0 }) +
  (if report.roundtrip_miniseed { 1 } else { 0 })
}

///|
/// Return a short artifact label for archival logs.
pub fn report_artifact_label(report : WorkflowReport) -> String {
  report.station +
  "." +
  report.channel +
  "@" +
  report.processed_samples.to_string()
}

///|
/// Return whether the processed trace still has usable timing metadata.
pub fn report_timing_is_valid(report : WorkflowReport) -> Bool {
  report.processed_duration >= 0.0 && report.processed_samples >= 0
}

///|
/// Return a deterministic integer suitable for a smoke-test assertion.
pub fn report_fingerprint(report : WorkflowReport) -> Int {
  report.source_samples +
  report.processed_samples +
  report.event_count +
  report_roundtrip_count(report)
}

///|
/// Return the report's processed sample rate proxy in samples per second.
pub fn report_sample_density(report : WorkflowReport) -> Double {
  if report.processed_duration <= 0.0 {
    0.0
  } else {
    report.processed_samples.to_double() / report.processed_duration
  }
}

///|
/// Return whether the report has a positive processed sample density.
pub fn report_has_samples(report : WorkflowReport) -> Bool {
  report_sample_density(report) > 0.0
}