// lang_pt.mbt — Portuguese number spelling (cardinal, year). Brazilian variant.
//
// Portuguese quirks handled here:
//   * the conjunction "e" links tens to units ("vinte e um") and hundreds to
//     the remainder ("cento e um", "duzentos e trinta e quatro");
//   * 100 is "cem" on its own but "cento" when a remainder follows;
//   * 200..900 use dedicated plural forms ("duzentos", "trezentos", ...);
//   * between scale groups, "e" appears only when the following group is
//     below 100 or an exact multiple of 100:
//       1001  -> "mil e um"        1100 -> "mil e cem"
//       1234  -> "mil duzentos e trinta e quatro"
//   * short scale: mil (10^3), milhao (10^6), bilhao (10^9), trilhao (10^12).

// Scale words for a group value of exactly 1. Index = group power.

///|
let pt_scale_sing : Array[String] = [
  "", "mil", "milhão", "bilhão", "trilhão", "quatrilhão", "quintilhão", "sextilhão",
]

// Scale words for group values >= 2. Index = group power.

///|
let pt_scale_plur : Array[String] = [
  "", "mil", "milhões", "bilhões", "trilhões", "quatrilhões", "quintilhões",
  "sextilhões",
]

// Hundreds: 2 -> "duzentos", 3 -> "trezentos", ... 9 -> "novecentos".

///|
let pt_hundreds : Array[String] = [
  "", "", "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos", "setecentos",
  "oitocentos", "novecentos",
]

///|
pub fn lang_pt() -> Lang {
  {
    variant: Pt,
    zero: "zero",
    ones: [
      "zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove",
    ],
    teens: [
      "dez", "onze", "doze", "treze", "catorze", "quinze", "dezesseis", "dezessete",
      "dezoito", "dezenove",
    ],
    tens: [
      "", "dez", "vinte", "trinta", "quarenta", "cinquenta", "sessenta", "setenta",
      "oitenta", "noventa",
    ],
    hundred: "cento",
    thousands: pt_scale_plur,
    negative: "menos",
    decimal: "vírgula",
    comma_sep: false,
  }
}

///|
fn Lang::below100_pt(self : Lang, r : Int) -> String {
  if r < 10 {
    return self.ones[r]
  }
  if r < 20 {
    return self.teens[r - 10]
  }
  let d = r / 10
  let u = r % 10
  if u == 0 {
    return self.tens[d]
  }
  // 21 -> "vinte e um", 32 -> "trinta e dois"
  return self.tens[d] + " e " + self.ones[u]
}

///|
fn Lang::triple_pt(self : Lang, t : Int) -> String {
  if t == 0 {
    return ""
  }
  let h = t / 100
  let r = t % 100
  if h == 0 {
    return self.below100_pt(r)
  }
  if h == 1 {
    // 100 -> "cem", 101 -> "cento e um", 110 -> "cento e dez"
    if r == 0 {
      return "cem"
    }
    return "cento e " + self.below100_pt(r)
  }
  if r == 0 {
    return pt_hundreds[h]
  }
  // 234 -> "duzentos e trinta e quatro"
  return pt_hundreds[h] + " e " + self.below100_pt(r)
}

///|
/// "e" joins a scale group to the next one when the next group is below 100
/// or an exact multiple of 100 ("mil e um", "mil e cem"); otherwise a plain
/// space is used ("mil duzentos e trinta e quatro").
fn pt_group_sep(next_triple : Int) -> String {
  if next_triple < 100 || next_triple % 100 == 0 {
    " e "
  } else {
    " "
  }
}

///|
fn Lang::cardinal_pt(self : Lang, n : BigInt) -> String {
  if n == BigInt::from_int(0) {
    return self.zero
  }
  if !self.supports(n) {
    return ""
  }
  let neg = n < BigInt::from_int(0)
  let n = if neg { -n } else { n }
  let groups = group3(n)
  let texts : Array[String] = []
  let triples : Array[Int] = []
  for i = 0; i < groups.length(); i = i + 1 {
    let (triple, power) = groups[i]
    let t = triple.to_int()
    if t == 0 {
      continue
    }
    let mut s = self.triple_pt(t)
    if power > 0 {
      if power == 1 {
        // 1000 -> "mil"; 2000 -> "dois mil"
        s = if t == 1 { "mil" } else { s + " mil" }
      } else if t == 1 {
        // 1000000 -> "um milhão"
        s = "um " + pt_scale_sing[power]
      } else {
        // 2000000 -> "dois milhões"
        s = s + " " + pt_scale_plur[power]
      }
    }
    texts.push(s)
    triples.push(t)
  }
  let mut joined = ""
  for i = 0; i < texts.length(); i = i + 1 {
    if i > 0 {
      joined = joined + pt_group_sep(triples[i])
    }
    joined = joined + texts[i]
  }
  if neg {
    "menos " + joined
  } else {
    joined
  }
}

///|
/// Portuguese years are read as a plain cardinal ("2024" ->
/// "dois mil e vinte e quatro"), so this delegates to `cardinal_pt`.
pub fn year_pt(n : BigInt) -> String {
  lang_pt().cardinal_pt(n)
}