///|
/// hmisc module demo - Harrell Miscellaneous Statistical Utilities.
///
/// Run: moon run examples/hmisc_demo
fn main {
  println("=== hmisc Module Demo ===")
  println("Harrell Miscellaneous Statistical Utilities")
  println("")

  // Sample data
  println("=== Sample Data ===")
  let data = @bio.hmisc_sample_data()
  let names = @bio.hmisc_sample_names()
  println("Variables: \{names.length()}")
  let mut i = 0
  while i < names.length() {
    println("  \{names[i]}: \{array_to_string(data[i])}")
    i = i + 1
  }
  println("")

  // Descriptive statistics
  println("=== Descriptive Statistics ===")
  i = 0
  while i < names.length() {
    let stats = @bio.hmisc_describe(data[i], name=names[i])
    println(@bio.hmisc_describe_summary(stats))
    println("")
    i = i + 1
  }

  // Pearson correlation
  println("=== Pearson Correlation ===")
  let pearson_corr = @bio.hmisc_rcorr(
    data,
    names~,
    cor_type=@bio.hmisc_cor_type_pearson(),
  )
  println(@bio.hmisc_rcorr_summary(pearson_corr))
  println("")

  // Spearman correlation
  println("=== Spearman Correlation ===")
  let spearman_corr = @bio.hmisc_rcorr(
    data,
    names~,
    cor_type=@bio.hmisc_cor_type_spearman(),
  )
  println(@bio.hmisc_rcorr_summary(spearman_corr))
  println("")

  // Variable clustering
  println("=== Variable Clustering ===")
  let vc_result = @bio.hmisc_varclus(data, names~, min_cluster_size=2)
  println(@bio.hmisc_varclus_summary(vc_result))
  println("Merge steps: \{vc_result.merges.length()}")
  let mut j = 0
  while j < vc_result.heights.length() {
    let step = vc_result.merges[j]
    println(
      "  Step \{j}: merge \{step[0]} and \{step[1]} at height \{hmisc_fmt(vc_result.heights[j], 4)}",
    )
    j = j + 1
  }
  println("")

  // Somers' d
  println("=== Somers' d Statistic ===")
  let x_data = data[0]
  let g1 : Array[Double] = []
  let g2 : Array[Double] = []
  let mut k = 0
  while k < x_data.length() {
    if x_data[k] <= 5.0 {
      g1.push(x_data[k])
    } else {
      g2.push(x_data[k])
    }
    k = k + 1
  }
  println("Group 1 (X <= 5): \{array_to_string(g1)}")
  println("Group 2 (X > 5): \{array_to_string(g2)}")
  let somers = @bio.hmisc_somers_d(g1, g2)
  println("Somers' d: \{hmisc_fmt(somers.d, 4)}")
  println(
    "  95% CI: [\{hmisc_fmt(somers.lower, 4)}, \{hmisc_fmt(somers.upper, 4)}]",
  )
  println("  n: \{somers.n}")
  println("")

  // Imputation with NaN values
  println("=== Imputation ===")
  let nan : Double = @double.not_a_number
  let messy_data = [
    [1.0, nan, 3.0, 4.0, nan, 6.0, 7.0, nan, 9.0, 10.0],
    [2.1, 3.9, nan, 8.0, 9.9, nan, 14.1, 16.0, nan, 20.0],
    [5.0, 4.0, 6.0, nan, 7.0, 5.0, nan, 4.0, 9.0, 6.0],
  ]
  println("Before imputation (NaN values present):")
  let mut r = 0
  while r < messy_data.length() {
    println("  Var \{names[r]}: \{array_to_string(messy_data[r])}")
    r = r + 1
  }
  let imputed = @bio.hmisc_impute(messy_data)
  println("After imputation (column means):")
  r = 0
  while r < imputed.length() {
    println("  Var \{names[r]}: \{array_to_string(imputed[r])}")
    r = r + 1
  }
  println("")
  println("=== Demo Complete ===")
}

///|
fn array_to_string(arr : Array[Double]) -> String {
  let mut result = "["
  let mut i = 0
  while i < arr.length() {
    if i > 0 {
      result = result + ", "
    }
    if arr[i].is_nan() {
      result = result + "NaN"
    } else {
      result = result + arr[i].to_string()
    }
    i = i + 1
  }
  result = result + "]"
  result
}

///|
fn hmisc_fmt(value : Double, decimals : Int32) -> String {
  if value.is_nan() {
    return "NaN"
  }
  let rounded = (value * @math.pow(10.0, decimals.to_double())).round() /
    @math.pow(10.0, decimals.to_double())
  let int_part = rounded.to_int()
  let dec_part = ((rounded - int_part.to_double()) *
    @math.pow(10.0, decimals.to_double()))
    .round()
    .to_int()
  if decimals == 0 {
    return "\{int_part}"
  }
  let sign = if value < 0.0 { "-" } else { "" }
  let dec_str = pad_zeros(dec_part, decimals)
  "\{sign}\{int_part}.\{dec_str}"
}

///|
fn pad_zeros(value : Int32, length : Int32) -> String {
  let abs_val = value.abs()
  let s = "\{abs_val}"
  if s.length() >= length {
    return s
  }
  let mut result = ""
  let mut i = 0
  while i < length - s.length() {
    result = result + "0"
    i = i + 1
  }
  result + s
}