///|
/// stageR module demo - two-stage hypothesis testing with OFDR control.
///
/// Demonstrates the stage-wise testing paradigm that controls the Overall
/// False Discovery Rate (OFDR) at the gene level while allowing post-hoc
/// assessment of individual confirmation hypotheses (e.g. transcript-level tests).
///
/// Reference: Van den Berge et al. (2017) Genome Biology 18:151.
/// Run: moon run examples/stage_r_demo
fn main {
  println("=== stageR Module Demo ===")
  println("Two-stage hypothesis testing with OFDR control")
  println("Reference: Bioconductor stageR")
  println("")

  // ------------------------------------------------------------------
  // 1. Load sample data
  // ------------------------------------------------------------------
  println("=== 1. Sample Data ===")
  let (pScreen, pConfirmation) = @bio.stage_r_sample()
  println("Genes: " + pScreen.length().to_string())
  println(
    "Confirmation hypotheses per gene: " + pConfirmation[0].length().to_string(),
  )
  println("Screening p-values: " + p_screen_to_string(pScreen))
  println("")

  // ------------------------------------------------------------------
  // 2. BH adjustment
  // ------------------------------------------------------------------
  println("=== 2. Benjamini-Hochberg FDR Adjustment ===")
  let bh_adj = @bio.stage_r_bh_adjust(pScreen)
  println("BH-adjusted screening p-values:")
  let mut i = 0
  while i < bh_adj.length() {
    println(
      "  Gene " +
      i.to_string() +
      ": raw=" +
      pScreen[i].to_string() +
      ", adj=" +
      bh_adj[i].to_string(),
    )
    i = i + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 3. Simes aggregation
  // ------------------------------------------------------------------
  println("=== 3. Simes Aggregation ===")
  let gene0_pvals = pConfirmation[0]
  println("Gene 0 confirmation p-values: " + p_conf_to_string(gene0_pvals))
  let simes = @bio.simes_aggregate(gene0_pvals)
  println("Simes aggregated p-value: " + simes.to_string())
  println("")

  // ------------------------------------------------------------------
  // 4. Stage-wise adjustment with Holm method
  // ------------------------------------------------------------------
  println("=== 4. Stage-wise Adjustment (Holm) ===")
  let config = @bio.StageRConfig::new(
    alpha=0.05,
    pScreenAdjusted=false,
    stageMethod=@bio.stage_r_method_holm(),
  )
  let result = @bio.stage_wise_adjustment(pScreen, pConfirmation, config)
  println("Total genes: " + result.nGenes.to_string())
  println(
    "Significant genes (screening): " + result.nSignificantGenes.to_string(),
  )
  println("Adjusted alpha (R/G * alpha): " + result.alphaAdjusted.to_string())
  println("")

  // ------------------------------------------------------------------
  // 5. Significant genes and hypotheses
  // ------------------------------------------------------------------
  println("=== 5. Significant Results ===")
  let sig_genes = @bio.get_significant_genes(result)
  println("Significant gene indices: " + int_array_to_string(sig_genes))
  let sig_hyps = @bio.get_significant_hypotheses(result)
  println(
    "Significant confirmation hypotheses: " + sig_hyps.length().to_string(),
  )
  let mut h = 0
  while h < sig_hyps.length() {
    let (g, j) = sig_hyps[h]
    println("  Gene " + g.to_string() + ", Hypothesis " + j.to_string())
    h = h + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 6. Results matrix
  // ------------------------------------------------------------------
  println("=== 6. Results Matrix (gene x hypothesis+1) ===")
  let mat = @bio.get_results(result)
  println("Column 0 = gene-level, Columns 1..H = confirmation")
  let mut gi = 0
  while gi < mat.length() {
    let row_str = bool_row_to_string(mat[gi])
    println("  Gene " + gi.to_string() + ": " + row_str)
    gi = gi + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 7. Compare methods
  // ------------------------------------------------------------------
  println("=== 7. Method Comparison ===")
  let methods = [
    ("none", @bio.stage_r_method_none()),
    ("holm", @bio.stage_r_method_holm()),
    ("dte", @bio.stage_r_method_dte()),
    ("dtu", @bio.stage_r_method_dtu()),
  ]
  let mut m = 0
  while m < methods.length() {
    let (name, method_) = methods[m]
    let cfg = @bio.StageRConfig::new(
      alpha=0.05,
      pScreenAdjusted=false,
      stageMethod=method_,
    )
    let res = @bio.stage_wise_adjustment(pScreen, pConfirmation, cfg)
    let sigs = @bio.get_significant_hypotheses(res)
    println(
      "  " + name + ": " + sigs.length().to_string() + " significant hypotheses",
    )
    m = m + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 8. Summary
  // ------------------------------------------------------------------
  println("=== 8. Summary ===")
  let summary = @bio.stage_r_summary(result)
  println(summary)
  println("=== Demo complete ===")
}

///|
fn p_screen_to_string(arr : Array[Double]) -> String {
  let buf = StringBuilder()
  buf.write_string("[")
  let mut i = 0
  while i < arr.length() {
    if i > 0 {
      buf.write_string(", ")
    }
    buf.write_string(arr[i].to_string())
    i = i + 1
  }
  buf.write_string("]")
  buf.to_string()
}

///|
fn p_conf_to_string(arr : Array[Double]) -> String {
  let buf = StringBuilder()
  buf.write_string("[")
  let mut i = 0
  while i < arr.length() {
    if i > 0 {
      buf.write_string(", ")
    }
    buf.write_string(arr[i].to_string())
    i = i + 1
  }
  buf.write_string("]")
  buf.to_string()
}

///|
fn int_array_to_string(arr : Array[Int32]) -> String {
  let buf = StringBuilder()
  buf.write_string("[")
  let mut i = 0
  while i < arr.length() {
    if i > 0 {
      buf.write_string(", ")
    }
    buf.write_string(arr[i].to_string())
    i = i + 1
  }
  buf.write_string("]")
  buf.to_string()
}

///|
fn bool_row_to_string(row : Array[Bool]) -> String {
  let buf = StringBuilder()
  buf.write_string("[")
  let mut i = 0
  while i < row.length() {
    if i > 0 {
      buf.write_string(", ")
    }
    buf.write_string(if row[i] { "TRUE" } else { "FALSE" })
    i = i + 1
  }
  buf.write_string("]")
  buf.to_string()
}