///|
fn print_feature(result : @src.Aldex2Result, name : String) -> Unit {
  let effect = match result.effects.find_feature(name) {
    Some(value) => value
    None => abort("ALDEx2 example feature not found: " + name)
  }
  let tests = match result.tests.find_feature(name) {
    Some(value) => value
    None => abort("ALDEx2 example test result not found: " + name)
  }
  println(
    "   " +
    name +
    ": effect=" +
    effect.effect.to_string() +
    ", overlap=" +
    effect.overlap.to_string() +
    ", Welch eBH=" +
    tests.welch_adjusted.to_string() +
    ", Wilcoxon eBH=" +
    tests.wilcoxon_adjusted.to_string(),
  )
}

///|
fn main {
  println("=== Bioconductor ALDEx2 Demo ===")
  let (counts, conditions, features, samples) = @src.aldex2_example_data()
  let config = @src.Aldex2Config::create(
    mc_samples=64,
    denominator=@src.Aldex2Iqlr,
    seed=2026,
  ) catch {
    _ => abort("failed to create ALDEx2 configuration")
  }

  println("\n1. Draw deterministic Dirichlet instances and apply IQLR")
  let clr = @src.aldex2_clr(
    counts,
    conditions,
    config~,
    feature_names=features,
    sample_names=samples,
  ) catch {
    Aldex2Error(message) => abort("failed to construct ALDEx2 CLR: " + message)
  }
  println(
    "   retained features=" +
    clr.feature_count().to_string() +
    ", removed all-zero features=" +
    clr.removed_feature_count().to_string() +
    ", samples=" +
    clr.sample_count().to_string() +
    ", Monte Carlo instances=" +
    clr.mc_sample_count().to_string(),
  )

  println("\n2. Estimate posterior tests and standardized effects")
  let result = @src.aldex2(
    counts,
    conditions,
    config~,
    feature_names=features,
    sample_names=samples,
  ) catch {
    Aldex2Error(message) => abort("failed to run ALDEx2: " + message)
  }
  print_feature(result, "increased")
  print_feature(result, "decreased")
  print_feature(result, "stable_high")
  print_feature(result, "rare_increased")

  println("\n3. Rank, select, and summarize compositional effects")
  let ranked = result.ranked()
  let summary = result.summary(maximum_adjusted=0.1, minimum_effect=1.0)
  println(
    "   largest absolute effect=" +
    ranked[0].feature_name +
    " (" +
    ranked[0].effect.to_string() +
    ")",
  )
  println(
    "   Welch eBH <= 0.10=" +
    summary.significant_welch_count.to_string() +
    ", |effect| >= 1=" +
    summary.large_effect_count.to_string() +
    ", jointly selected=" +
    result.select(maximum_adjusted=0.1, minimum_effect=1.0).length().to_string(),
  )

  println("\n4. Compute posterior expected Aitchison distances")
  let distances = result.clr.expected_distance()
  println(
    "   distance(C1, T1)=" +
    distances[0][4].to_string() +
    ", symmetric=" +
    (distances[0][4] == distances[4][0]).to_string(),
  )

  println("\n5. Add posterior summaries to an immutable container copy")
  let assays : Map[String, Array[Array[Double]]] = Map([("counts", counts)])
  let metadata : Map[String, String] = Map([("source", "aldex2_demo")])
  let experiment = @src.summarized_experiment(assays, [], [], metadata)
  let output = @src.aldex2_summarized_experiment(
    experiment,
    conditions,
    config~,
    feature_names=features,
    sample_names=samples,
  ) catch {
    Aldex2Error(message) =>
      abort("failed to integrate ALDEx2 with SummarizedExperiment: " + message)
  }
  let effect_assay = match @src.se_assay(output.experiment, "aldex2_effect") {
    Some(value) => value
    None => abort("ALDEx2 effect assay missing")
  }
  println(
    "   effect rows=" +
    effect_assay.length().to_string() +
    ", source object unchanged=" +
    (@src.se_assay(experiment, "aldex2_effect") is None).to_string(),
  )

  println("\n6. Export an ALDEx2-compatible tabular summary")
  println(result.to_tsv())

  println("7. Invalid count matrices produce explicit diagnostics")
  let rejected = try {
    ignore(
      @src.aldex2([[2.0, -1.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]], [
        "A", "A", "B", "B",
      ]),
    )
    false
  } catch {
    Aldex2Error(message) => {
      println("   " + message)
      true
    }
  }
  println("   malformed counts rejected=" + rejected.to_string())
  println("\n=== Demo Complete ===")
}