///|
/// A deterministic import gate built from table quality and structural checks.
pub(all) struct QualityGateReport {
  passed : Bool
  quality_score : Int
  density_score : Int
  duplicate_row_count : Int
  missing_columns : Array[String]
  reasons : Array[String]
} derive(Eq)

///|
fn quality_gate_threshold(value : Int) -> Int {
  clamp_percent(value)
}

///|
fn quality_gate_join(values : Array[String], separator : String) -> String {
  if values.length() == 0 {
    "none"
  } else {
    let out = StringBuilder::StringBuilder()
    let mut i = 0
    while i < values.length() {
      if i > 0 {
        out.write_string(separator)
      }
      out.write_string(values[i])
      i = i + 1
    }
    out.to_string()
  }
}

///|
fn quality_gate_add_score_reason(
  reasons : Array[String],
  label : String,
  actual : Int,
  minimum : Int,
) -> Unit {
  if actual < minimum {
    let text =
      $|\{label} score \{actual} is below minimum \{minimum}
    reasons.push(text)
  }
}

///|
fn quality_gate_add_missing_reason(
  reasons : Array[String],
  missing : Array[String],
) -> Unit {
  if missing.length() > 0 {
    let names = quality_gate_join(missing, ", ")
    let text =
      $|missing required columns: \{names}
    reasons.push(text)
  }
}

///|
fn quality_gate_add_duplicate_reason(
  reasons : Array[String],
  duplicate_count : Int,
  reject_duplicates : Bool,
) -> Unit {
  if reject_duplicates && duplicate_count > 0 {
    let text =
      $|duplicate rows detected: \{duplicate_count}
    reasons.push(text)
  }
}

///|
/// Check whether a table is safe to pass into an import or release workflow.
/// Thresholds are clamped to the inclusive range 0..100.
pub fn Table::quality_gate(
  self : Table,
  min_quality_score : Int,
  min_density_score : Int,
  required_columns : Array[String],
  reject_duplicates : Bool,
) -> QualityGateReport {
  let minimum_quality = quality_gate_threshold(min_quality_score)
  let minimum_density = quality_gate_threshold(min_density_score)
  let prof = profile(self)
  let stats = table_stats(self)
  let missing = self.missing_columns(required_columns)
  let reasons : Array[String] = []
  quality_gate_add_score_reason(
    reasons,
    "quality",
    prof.quality_score,
    minimum_quality,
  )
  quality_gate_add_score_reason(
    reasons,
    "density",
    stats.density_score,
    minimum_density,
  )
  quality_gate_add_missing_reason(reasons, missing)
  quality_gate_add_duplicate_reason(
    reasons,
    stats.duplicate_row_count,
    reject_duplicates,
  )
  {
    passed: reasons.length() == 0,
    quality_score: prof.quality_score,
    density_score: stats.density_score,
    duplicate_row_count: stats.duplicate_row_count,
    missing_columns: missing,
    reasons,
  }
}

///|
pub fn QualityGateReport::summary(self : QualityGateReport) -> String {
  let status = if self.passed { "passed" } else { "failed" }
  let reasons = quality_gate_join(self.reasons, "; ")
  let text =
    $|\{status}: quality=\{self.quality_score}, density=\{self.density_score}, duplicates=\{self.duplicate_row_count}, reasons=\{reasons}
  text
}

///|
fn quality_gate_markdown_row(
  out : StringBuilder,
  name : String,
  value : String,
) -> Unit {
  out.write_string("| ")
  out.write_string(markdown_escape_cell(name))
  out.write_string(" | ")
  out.write_string(markdown_escape_cell(value))
  out.write_string(" |\n")
}

///|
/// Render gate evidence as a compact Markdown table for CI or review records.
pub fn QualityGateReport::to_markdown(self : QualityGateReport) -> String {
  let out = StringBuilder::StringBuilder()
  quality_gate_markdown_row(out, "metric", "value")
  quality_gate_markdown_row(out, "---", "---")
  quality_gate_markdown_row(
    out,
    "status",
    if self.passed {
      "passed"
    } else {
      "failed"
    },
  )
  quality_gate_markdown_row(
    out,
    "quality_score",
    self.quality_score.to_string(),
  )
  quality_gate_markdown_row(
    out,
    "density_score",
    self.density_score.to_string(),
  )
  quality_gate_markdown_row(
    out,
    "duplicate_row_count",
    self.duplicate_row_count.to_string(),
  )
  quality_gate_markdown_row(
    out,
    "missing_columns",
    quality_gate_join(self.missing_columns, ", "),
  )
  quality_gate_markdown_row(
    out,
    "reasons",
    quality_gate_join(self.reasons, "; "),
  )
  out.to_string()
}