///|
/// Summary statistics for a compiled dictionary.
pub(all) struct DictionaryStats {
  entry_count : Int
  node_count : Int
  label_count : Int
  min_keyword_length : Int
  max_keyword_length : Int
  total_keyword_length : Int
} derive(Debug, Eq, ToJson)

///|
pub fn Lexicon::stats(self : Lexicon) -> DictionaryStats {
  let labels : Map[String, Bool] = Map([])
  let mut min_length = 0
  let mut max_length = 0
  let mut total = 0
  for item in self.entries {
    let length = item.keyword.length()
    if min_length == 0 || length < min_length {
      min_length = length
    }
    if length > max_length {
      max_length = length
    }
    total = total + length
    labels[item.label] = true
  }
  {
    entry_count: self.entries.length(),
    node_count: self.nodes.length(),
    label_count: labels.length(),
    min_keyword_length: min_length,
    max_keyword_length: max_length,
    total_keyword_length: total,
  }
}

///|
/// Estimate prefix-sharing efficiency as a percentage.
pub fn DictionaryStats::sharing_percent(self : DictionaryStats) -> Int {
  if self.total_keyword_length == 0 {
    100
  } else {
    100 - self.node_count * 100 / (self.total_keyword_length + 1)
  }
}

///|
/// Return aggregate counts for matches and distinct surfaces.
pub(all) struct MatchStats {
  match_count : Int
  distinct_surface_count : Int
  total_weight : Int
  longest_span : Int
} derive(Debug, Eq, ToJson)

///|
pub fn match_stats(matches : ArrayView[LexiconMatch]) -> MatchStats {
  let surfaces : Map[String, Bool] = Map([])
  let mut total = 0
  let mut longest = 0
  for hit in matches {
    surfaces[hit.keyword] = true
    total = total + hit.weight
    let span = hit.end - hit.start
    if span > longest {
      longest = span
    }
  }
  {
    match_count: matches.length(),
    distinct_surface_count: surfaces.length(),
    total_weight: total,
    longest_span: longest,
  }
}