///|
/// EnrichedHeatmap module demo - genomic signal normalization.
///
/// Demonstrates normalization of genomic signals (e.g. CpG methylation,
/// histone marks) to target regions (e.g. TSS, promoters) for visualization
/// as enriched heatmaps.
///
/// Reference: Gu, Eils & Schlesner (2018) BMC Genomics 19:234.
/// Run: moon run examples/enriched_heatmap_demo
fn main {
  println("=== EnrichedHeatmap Module Demo ===")
  println("Genomic signal normalization for enriched heatmaps")
  println("Reference: Bioconductor EnrichedHeatmap")
  println("")

  // ------------------------------------------------------------------
  // 1. Load sample data
  // ------------------------------------------------------------------
  println("=== 1. Sample Data ===")
  let (signals, targets) = @bio.enriched_heatmap_sample()
  println("Signals: " + signals.length().to_string())
  println("Targets: " + targets.length().to_string())
  println(
    "Target 0: " +
    targets[0].chr +
    ":" +
    targets[0].start.to_string() +
    "-" +
    targets[0].end_.to_string() +
    " (" +
    targets[0].strand +
    ")",
  )
  println("")

  // ------------------------------------------------------------------
  // 2. Basic normalization
  // ------------------------------------------------------------------
  println("=== 2. Basic Normalization ===")
  let config = @bio.EnrichedHeatmapConfig::new(
    extendUp=5000,
    extendDown=5000,
    w=500,
    k=0,
    meanMode=@bio.mean_mode_absolute(),
    includeTarget=false,
    smooth=false,
    smoothWindow=5,
    background=0.0,
    flipUpstream=false,
    keepLow=0.0,
    keepHigh=1.0,
  )
  let mat = @bio.normalize_to_matrix(signals, targets, config)
  println(
    "Matrix dimensions: " +
    mat.nRows.to_string() +
    " x " +
    mat.nCols.to_string(),
  )
  println("Upstream windows: " + mat.upstreamIndex.length().to_string())
  println("Downstream windows: " + mat.downstreamIndex.length().to_string())
  println("")

  // ------------------------------------------------------------------
  // 3. Normalization with target body
  // ------------------------------------------------------------------
  println("=== 3. With Target Body (k=5) ===")
  let config_t = @bio.EnrichedHeatmapConfig::new(
    extendUp=5000,
    extendDown=5000,
    w=500,
    k=5,
    meanMode=@bio.mean_mode_absolute(),
    includeTarget=true,
    smooth=false,
    smoothWindow=5,
    background=0.0,
    flipUpstream=false,
    keepLow=0.0,
    keepHigh=1.0,
  )
  let mat_t = @bio.normalize_to_matrix(signals, targets, config_t)
  println(
    "Matrix dimensions: " +
    mat_t.nRows.to_string() +
    " x " +
    mat_t.nCols.to_string(),
  )
  println("Upstream windows: " + mat_t.upstreamIndex.length().to_string())
  println("Target windows: " + mat_t.targetIndex.length().to_string())
  println("Downstream windows: " + mat_t.downstreamIndex.length().to_string())
  println("")

  // ------------------------------------------------------------------
  // 4. Mean mode comparison
  // ------------------------------------------------------------------
  println("=== 4. Mean Mode Comparison ===")
  let modes = [
    ("absolute", @bio.mean_mode_absolute()),
    ("weighted", @bio.mean_mode_weighted()),
    ("w0", @bio.mean_mode_w0()),
    ("coverage", @bio.mean_mode_coverage()),
  ]
  let mut m = 0
  while m < modes.length() {
    let (name, mode) = modes[m]
    let cfg = @bio.EnrichedHeatmapConfig::new(
      extendUp=1000,
      extendDown=1000,
      w=100,
      k=0,
      meanMode=mode,
      includeTarget=false,
      smooth=false,
      smoothWindow=5,
      background=0.0,
      flipUpstream=false,
      keepLow=0.0,
      keepHigh=1.0,
    )
    let res = @bio.normalize_to_matrix(signals, targets, cfg)
    let profile = @bio.enrichment_profile(res)
    let profile_mean = array_mean(profile)
    println("  " + name + ": mean profile value = " + profile_mean.to_string())
    m = m + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 5. Smoothing
  // ------------------------------------------------------------------
  println("=== 5. Row Smoothing ===")
  let config_s = @bio.EnrichedHeatmapConfig::new(
    extendUp=5000,
    extendDown=5000,
    w=500,
    k=0,
    meanMode=@bio.mean_mode_absolute(),
    includeTarget=false,
    smooth=true,
    smoothWindow=5,
    background=0.0,
    flipUpstream=false,
    keepLow=0.0,
    keepHigh=1.0,
  )
  let mat_s = @bio.normalize_to_matrix(signals, targets, config_s)
  println("Smoothed: " + mat_s.smooth.to_string())
  println("Failed rows: " + mat_s.failedRows.length().to_string())
  println("")

  // ------------------------------------------------------------------
  // 6. Row means
  // ------------------------------------------------------------------
  println("=== 6. Row Means (per-target enrichment) ===")
  let means = @bio.eh_row_means(mat)
  println("Row means (first 5 targets):")
  let mut r = 0
  while r < 5 && r < means.length() {
    println("  Target " + r.to_string() + ": " + means[r].to_string())
    r = r + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 7. Enrichment profile
  // ------------------------------------------------------------------
  println("=== 7. Enrichment Profile (column-wise mean) ===")
  let profile = @bio.enrichment_profile(mat)
  println("Profile length: " + profile.length().to_string())
  println("Profile values (first 5):")
  let mut p = 0
  while p < 5 && p < profile.length() {
    println("  Window " + p.to_string() + ": " + profile[p].to_string())
    p = p + 1
  }
  println("")

  // ------------------------------------------------------------------
  // 8. Minus strand handling
  // ------------------------------------------------------------------
  println("=== 8. Minus Strand Handling ===")
  let m_signals = [
    @bio.GenomicSignal::new("chr1", 9800, 9900, 0.5),
    @bio.GenomicSignal::new("chr1", 10100, 10200, 1.0),
  ]
  let m_targets = [@bio.TargetRegion::new("chr1", 10000, 10000, "-")]
  let m_config = @bio.EnrichedHeatmapConfig::new(
    extendUp=500,
    extendDown=500,
    w=500,
    k=0,
    meanMode=@bio.mean_mode_absolute(),
    includeTarget=false,
    smooth=false,
    smoothWindow=5,
    background=0.0,
    flipUpstream=false,
    keepLow=0.0,
    keepHigh=1.0,
  )
  let m_mat = @bio.normalize_to_matrix(m_signals, m_targets, m_config)
  println(
    "Minus strand target: " +
    m_targets[0].chr +
    ":" +
    m_targets[0].start.to_string() +
    " (" +
    m_targets[0].strand +
    ")",
  )
  println(
    "Matrix: " + m_mat.nRows.to_string() + " x " + m_mat.nCols.to_string(),
  )
  println("Window 0 (upstream, reversed): " + m_mat.matrix[0][0].to_string())
  println("Window 1 (downstream, reversed): " + m_mat.matrix[0][1].to_string())
  println("")

  // ------------------------------------------------------------------
  // 9. Summary
  // ------------------------------------------------------------------
  println("=== 9. Summary ===")
  let summary = @bio.enriched_heatmap_summary(mat)
  println(summary)
  println("=== Demo complete ===")
}

///|
fn array_mean(arr : Array[Double]) -> Double {
  if arr.length() == 0 {
    return 0.0
  }
  let mut sum = 0.0
  let mut i = 0
  while i < arr.length() {
    sum = sum + arr[i]
    i = i + 1
  }
  sum / arr.length().to_double()
}