///|
/// 词典标识。命名与 zxcvbn-rs 的 `DictionaryType` 对齐,便于差分对拍时对照。
pub enum Dictionary {
  Passwords
  English
  FemaleNames
  MaleNames
  Surnames
  UsTvAndFilm
  UserInputs
} derive(Eq, Debug)

///|
pub extend Dictionary with Eq::{equal, not_equal}

///|
pub extend Dictionary with @debug.Debug::{to_repr}

///|
/// 由有序词表构建 rank 表。
///
/// rank 为 1-based 行序;重复词**后者覆盖前者**——与上游 `build_ranked_dict`
/// (JS 对象逐个赋值)及 zxcvbn-rs(HashMap `collect`)的语义保持一致。
pub fn build_ranked_dict(words : Array[String]) -> Map[String, Int] {
  let m : Map[String, Int] = Map([])
  let mut i = 0
  while i < words.length() {
    m[words[i]] = i + 1
    i += 1
  }
  m
}

///|
/// 6 个内置频率词典,首次使用时惰性构建。
/// 数据本体在 `frequency_data.mbt`(由 tools/gen_dictionaries.py 生成)。
let passwords_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(passwords_list())
})

///|
let english_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(english_wikipedia_list())
})

///|
let female_names_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(female_names_list())
})

///|
let male_names_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(male_names_list())
})

///|
let surnames_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(surnames_list())
})

///|
let us_tv_and_film_dict : Lazy[Map[String, Int]] = Lazy(() => {
  build_ranked_dict(us_tv_and_film_list())
})

///|
/// 在全部内置词典中查词,返回 `(词典, rank)`。
///
/// 查询顺序与上游 `RANKED_DICTIONARIES` 的构造顺序一致:
/// passwords → english → female_names → male_names → surnames → us_tv_and_film。
/// 惰性求值短路:在靠前的词典命中时不会强制构建后续词典。
pub fn ranked_lookup(word : String) -> (Dictionary, Int)? {
  let dicts : Array[(Lazy[Map[String, Int]], Dictionary)] = [
    (passwords_dict, Passwords),
    (english_dict, English),
    (female_names_dict, FemaleNames),
    (male_names_dict, MaleNames),
    (surnames_dict, Surnames),
    (us_tv_and_film_dict, UsTvAndFilm),
  ]
  for pair in dicts {
    match pair.0.force().get(word) {
      Some(r) => return Some((pair.1, r))
      None => ()
    }
  }
  None
}

///|
/// 全部内置频率词典,顺序与上游 `RANKED_DICTIONARIES` 的构造顺序一致。
/// 匹配器(dictionary_match / reverse_dictionary_match / l33t_match)按这个顺序遍历。
pub let builtin_dictionaries : Array[(Dictionary, Lazy[Map[String, Int]])] = [
  (Passwords, passwords_dict),
  (English, english_dict),
  (FemaleNames, female_names_dict),
  (MaleNames, male_names_dict),
  (Surnames, surnames_dict),
  (UsTvAndFilm, us_tv_and_film_dict),
]

///|
/// 内置词典中最长词条的**字符数**(按 Unicode 标量值计)。
///
/// `dictionary_match` 只需枚举到这个长度:更长的子串不可能命中任何词条。
/// 这是与上游**语义完全等价**的裁剪(上游枚举全部长度,结果必然为空),
/// 但把词典匹配从 O(n²) 次哈希查询降到 O(n × 最长词长),长密码收益巨大。
pub let max_dictionary_word_length : Lazy[Int] = Lazy(() => {
  let lists : Array[Array[String]] = [
    passwords_list(),
    english_wikipedia_list(),
    female_names_list(),
    male_names_list(),
    surnames_list(),
    us_tv_and_film_list(),
  ]
  let mut longest = 1
  for list in lists {
    for word in list {
      let len = word.to_array().length()
      if len > longest {
        longest = len
      }
    }
  }
  longest
})

///|
/// `frequency_lists.coffee` 在 ASCII 小写字母域内过滤,但词典里确实存在少量
/// 非 ASCII 词条。这里把它们转成 ASCII 小写以对齐 `Array[Char]` 的匹配口径。
pub fn to_ascii_lower(chars : Array[Char]) -> Array[Char] {
  chars.map(c => c.to_ascii_lowercase())
}