///|
pub(all) enum RecordDiffKind {
  Added
  Removed
  Changed
} derive(Debug, Eq)

///|
pub(all) struct RecordDiff {
  kind : RecordDiffKind
  key : String
  left : VcfRecord?
  right : VcfRecord?
} derive(Debug, Eq)

///|
pub fn diff_documents(
  left : VcfDocument,
  right : VcfDocument,
) -> Array[RecordDiff] {
  let diffs : Array[RecordDiff] = []
  for record in left.records {
    let key = record_key(record)
    match find_record(right.records, key) {
      None =>
        diffs.push({
          kind: RecordDiffKind::Removed,
          key,
          left: Some(record),
          right: None,
        })
      Some(other) if other != record =>
        diffs.push({
          kind: RecordDiffKind::Changed,
          key,
          left: Some(record),
          right: Some(other),
        })
      Some(_) => ()
    }
    if find_record(right.records, key) is None {
      match find_locus(right.records, record_locus_key(record)) {
        Some(other) => {
          ignore(diffs.pop())
          diffs.push({
            kind: RecordDiffKind::Changed,
            key,
            left: Some(record),
            right: Some(other),
          })
        }
        None => ()
      }
    }
  }
  for record in right.records {
    let key = record_key(record)
    if find_record(left.records, key) is None &&
      find_locus(left.records, record_locus_key(record)) is None {
      diffs.push({
        kind: RecordDiffKind::Added,
        key,
        left: None,
        right: Some(record),
      })
    }
  }
  diffs
}

///|
fn record_locus_key(record : VcfRecord) -> String {
  "\{record.chrom}:\{record.pos}:\{record.ref_allele}"
}

///|
pub fn record_key(record : VcfRecord) -> String {
  let alts = record.alt_alleles.join(",")
  "\{record.chrom}:\{record.pos}:\{record.ref_allele}>\{alts}"
}

///|
fn find_record(records : Array[VcfRecord], key : String) -> VcfRecord? {
  for record in records {
    if record_key(record) == key {
      return Some(record)
    }
  }
  None
}

///|
fn find_locus(records : Array[VcfRecord], key : String) -> VcfRecord? {
  for record in records {
    if record_locus_key(record) == key {
      return Some(record)
    }
  }
  None
}