///|
/// Bloom filter and k-mer counting demo.
///
/// Demonstrates:
/// 1. Bloom filter for approximate set membership
/// 2. Exact k-mer counting with hash map
/// 3. Bloom-based approximate k-mer presence filtering
///
/// Run: moon run examples/bloom_filter_demo/main.mbt
fn main {
  println("=== Bloom Filter & K-mer Counting Demo ===")
  println("")

  // --- 1. Bloom Filter Basics ---
  println("1. Bloom Filter Basics:")
  let bf = @bio.BloomFilter::new(100, 0.01)
  println("   Capacity (bits): \{@bio.BloomFilter::capacity(bf)}")
  println("   Hash functions: \{@bio.BloomFilter::hash_count(bf)}")
  @bio.BloomFilter::insert(bf, "ACGTACGT")
  @bio.BloomFilter::insert(bf, "TTTTGGGG")
  @bio.BloomFilter::insert(bf, "CCCCAAAA")
  println("   Items inserted: \{@bio.BloomFilter::len(bf)}")
  println("   Bits set: \{@bio.BloomFilter::bits_set(bf)}")
  println(
    "   Contains 'ACGTACGT': \{@bio.BloomFilter::contains(bf, "ACGTACGT")}",
  )
  println(
    "   Contains 'GTGTCACA': \{@bio.BloomFilter::contains(bf, "GTGTCACA")}",
  )
  println("   Estimated FPR: \{@bio.BloomFilter::estimated_fpr(bf)}")
  println("")

  // --- 2. No False Negatives ---
  println("2. No False Negatives (all inserted items found):")
  let bf2 = @bio.BloomFilter::new(500, 0.05)
  let kmers = ["ACGT", "CGTA", "GTAC", "TACG", "AAAA", "TTTT", "GGGG", "CCCC"]
  for i = 0; i < kmers.length(); i = i + 1 {
    @bio.BloomFilter::insert(bf2, kmers[i])
  }
  let mut all_found = true
  for i = 0; i < kmers.length(); i = i + 1 {
    if !@bio.BloomFilter::contains(bf2, kmers[i]) {
      all_found = false
    }
  }
  println("   All \{kmers.length()} items found: \{all_found}")
  println("   Estimated FPR: \{@bio.BloomFilter::estimated_fpr(bf2)}")
  println("")

  // --- 3. Clear and Reuse ---
  println("3. Clear and Reuse:")
  let bf3 = @bio.BloomFilter::with_params(1000, 3)
  @bio.BloomFilter::insert(bf3, "test1")
  @bio.BloomFilter::insert(bf3, "test2")
  println(
    "   Before clear: \{@bio.BloomFilter::len(bf3)} items, \{@bio.BloomFilter::bits_set(bf3)} bits set",
  )
  @bio.BloomFilter::clear(bf3)
  println(
    "   After clear: \{@bio.BloomFilter::len(bf3)} items, \{@bio.BloomFilter::bits_set(bf3)} bits set",
  )
  @bio.BloomFilter::insert(bf3, "new_item")
  println(
    "   After re-insert: \{@bio.BloomFilter::len(bf3)} items, \{@bio.BloomFilter::bits_set(bf3)} bits set",
  )
  println("")

  // --- 4. Exact K-mer Counting ---
  println("4. Exact K-mer Counting (k=3):")
  let kc = @bio.KmerCounter::new(3)
  @bio.KmerCounter::count(kc, "ACGTACGTACGT")
  println("   Sequence: ACGTACGTACGT")
  println("   k = \{@bio.KmerCounter::k(kc)}")
  println("   Total k-mers: \{@bio.KmerCounter::total(kc)}")
  println("   Unique k-mers: \{@bio.KmerCounter::unique(kc)}")
  println("   Count of 'ACG': \{@bio.KmerCounter::get(kc, "ACG")}")
  println("   Count of 'CGT': \{@bio.KmerCounter::get(kc, "CGT")}")
  println("   Count of 'GTA': \{@bio.KmerCounter::get(kc, "GTA")}")
  println("   Count of 'TTT': \{@bio.KmerCounter::get(kc, "TTT")}")
  println("")

  // --- 5. Top-k K-mers ---
  println("5. Top K-mers:")
  let top = @bio.KmerCounter::top_k(kc, 3)
  println("   Top 3 k-mers by count:")
  for i = 0; i < top.length(); i = i + 1 {
    println("     \{top[i].kmer()}: \{top[i].count()}")
  }
  println("")

  // --- 6. Multiple Sequence Counting ---
  println("6. Multiple Sequence Counting:")
  let kc2 = @bio.KmerCounter::new(4)
  @bio.KmerCounter::count(kc2, "ACGTACGT")
  @bio.KmerCounter::count(kc2, "ACGTAAAA")
  @bio.KmerCounter::count(kc2, "TTTTACGT")
  println("   Sequences: ACGTACGT, ACGTAAAA, TTTTACGT")
  println("   k = 4")
  println("   Total k-mers: \{@bio.KmerCounter::total(kc2)}")
  println("   Unique k-mers: \{@bio.KmerCounter::unique(kc2)}")
  println("   Count of 'ACGT': \{@bio.KmerCounter::get(kc2, "ACGT")}")
  println("")

  // --- 7. Bloom-based K-mer Filter ---
  println("7. Bloom-based K-mer Filter:")
  let bkf = @bio.BloomKmerFilter::new(3, 1000, 0.01)
  @bio.BloomKmerFilter::add_sequence(bkf, "ACGTACGTACGT")
  println("   Sequence indexed: ACGTACGTACGT")
  println("   k = \{@bio.BloomKmerFilter::k(bkf)}")
  println("   Items inserted: \{@bio.BloomKmerFilter::len(bkf)}")
  println("   Filter capacity: \{@bio.BloomKmerFilter::capacity(bkf)} bits")
  println("   Hash functions: \{@bio.BloomKmerFilter::hash_count(bkf)}")
  println("   Contains 'ACG': \{@bio.BloomKmerFilter::contains(bkf, "ACG")}")
  println("   Contains 'TTT': \{@bio.BloomKmerFilter::contains(bkf, "TTT")}")
  println("")

  // --- 8. Count Distinct K-mers ---
  println("8. Count Distinct K-mers (approximate):")
  let bkf2 = @bio.BloomKmerFilter::new(3, 10000, 0.001)
  let (distinct, duplicate) = @bio.BloomKmerFilter::count_distinct(
    bkf2, "ACGTACGT",
  )
  println("   Sequence: ACGTACGT")
  println("   Distinct k-mers: \{distinct}")
  println("   Duplicate k-mers: \{duplicate}")
  println("   Total k-mers: \{distinct + duplicate}")
  println("")

  // --- 9. FPR Comparison ---
  println("9. False Positive Rate Comparison:")
  let fpr_values = [0.001, 0.01, 0.05, 0.10]
  for i = 0; i < fpr_values.length(); i = i + 1 {
    let bf_fpr = @bio.BloomFilter::new(100, fpr_values[i])
    println(
      "   FPR=\{fpr_values[i]}: bits=\{@bio.BloomFilter::capacity(bf_fpr)}, hashes=\{@bio.BloomFilter::hash_count(bf_fpr)}",
    )
  }
  println("")

  // --- 10. Large-scale Simulation ---
  println("10. Large-scale Simulation (1000 items):")
  let bf_large = @bio.BloomFilter::new(1000, 0.01)
  for i = 0; i < 100; i = i + 1 {
    @bio.BloomFilter::insert(bf_large, "kmer_\{i}")
  }
  println("   Inserted: \{@bio.BloomFilter::len(bf_large)} items")
  println("   Bits set: \{@bio.BloomFilter::bits_set(bf_large)}")
  println("   Estimated FPR: \{@bio.BloomFilter::estimated_fpr(bf_large)}")
  // Verify no false negatives
  let mut found = 0
  for i = 0; i < 100; i = i + 1 {
    if @bio.BloomFilter::contains(bf_large, "kmer_\{i}") {
      found = found + 1
    }
  }
  println("   Found \{found}/100 inserted items (should be 100)")
  println("")

  println("=== Bloom Filter & K-mer Counting Demo Complete ===")
}