///|
pub fn summarize(document : VcfDocument) -> VcfStats {
  let contigs : Array[String] = []
  let filters : Array[String] = []
  let info_keys : Array[String] = []
  let variant_types : Array[String] = []
  let mut multiallelic_count = 0
  for record in document.records {
    contigs.push(record.chrom)
    if record.alt_alleles.length() > 1 {
      multiallelic_count = multiallelic_count + 1
    }
    collect_filters(record, filters)
    collect_info_keys(record, info_keys)
    collect_variant_types(record, variant_types)
  }
  {
    record_count: document.records.length(),
    contig_counts: count_keys(contigs),
    filter_counts: count_keys(filters),
    info_counts: count_keys(info_keys),
    variant_type_counts: count_keys(variant_types),
    sample_count: document.header.samples.length(),
    multiallelic_count,
  }
}

///|
pub fn format_stats(stats : VcfStats) -> String {
  let builder = StringBuilder()
  builder.write_string("records\t\{stats.record_count}\n")
  builder.write_string("samples\t\{stats.sample_count}\n")
  builder.write_string("multiallelic\t\{stats.multiallelic_count}\n")
  write_counts(builder, "contig", stats.contig_counts)
  write_counts(builder, "filter", stats.filter_counts)
  write_counts(builder, "info", stats.info_counts)
  write_counts(builder, "variant", stats.variant_type_counts)
  builder.to_string()
}

///|
fn collect_filters(record : VcfRecord, filters : Array[String]) -> Unit {
  if record.filters.length() == 0 {
    filters.push(".")
  } else {
    for item in record.filters {
      filters.push(item)
    }
  }
}

///|
fn collect_info_keys(record : VcfRecord, info_keys : Array[String]) -> Unit {
  for pair in record.info {
    let (key, _) = pair
    info_keys.push(key)
  }
}

///|
fn collect_variant_types(
  record : VcfRecord,
  variant_types : Array[String],
) -> Unit {
  if record.alt_alleles.length() == 0 {
    variant_types.push("NO_ALT")
  } else {
    for alt in record.alt_alleles {
      variant_types.push(classify_variant(record.ref_allele, alt))
    }
  }
}

///|
fn classify_variant(ref_allele : String, alt_allele : String) -> String {
  if alt_allele.has_prefix("<") ||
    alt_allele.contains("[") ||
    alt_allele.contains("]") {
    "SYMBOLIC"
  } else if ref_allele.length() == 1 && alt_allele.length() == 1 {
    "SNV"
  } else if ref_allele.length() < alt_allele.length() {
    "INS"
  } else if ref_allele.length() > alt_allele.length() {
    "DEL"
  } else if ref_allele.length() == alt_allele.length() {
    "MNV"
  } else {
    "COMPLEX"
  }
}

///|
fn count_keys(keys : Array[String]) -> Array[(String, Int)] {
  let counts : Array[(String, Int)] = []
  for key in keys {
    if !has_count(counts, key) {
      counts.push((key, count_matching(keys, key)))
    }
  }
  counts
}

///|
fn has_count(counts : Array[(String, Int)], key : String) -> Bool {
  for pair in counts {
    let (item_key, _) = pair
    if item_key == key {
      return true
    }
  }
  false
}

///|
fn count_matching(keys : Array[String], needle : String) -> Int {
  let mut count = 0
  for key in keys {
    if key == needle {
      count = count + 1
    }
  }
  count
}

///|
fn write_counts(
  builder : StringBuilder,
  label : String,
  counts : Array[(String, Int)],
) -> Unit {
  for pair in counts {
    let (key, count) = pair
    builder.write_string("\{label}\t\{key}\t\{count}\n")
  }
}