///|
pub(all) struct TagBuilder {
  language : String
  extlang : Array[String]
  script : String
  region : String
  variants : Array[String]
  extensions : Array[Extension]
  private_use : Array[String]
}

///|
pub fn builder(language : String) -> TagBuilder {
  {
    language,
    extlang: [],
    script: "",
    region: "",
    variants: [],
    extensions: [],
    private_use: [],
  }
}

///|
pub fn TagBuilder::with_extlang(
  self : TagBuilder,
  extlang : String,
) -> TagBuilder {
  let next = self.extlang.copy()
  next.push(extlang)
  {
    language: self.language,
    extlang: next,
    script: self.script,
    region: self.region,
    variants: self.variants.copy(),
    extensions: self.extensions.copy(),
    private_use: self.private_use.copy(),
  }
}

///|
pub fn TagBuilder::with_script(
  self : TagBuilder,
  script : String,
) -> TagBuilder {
  {
    language: self.language,
    extlang: self.extlang.copy(),
    script,
    region: self.region,
    variants: self.variants.copy(),
    extensions: self.extensions.copy(),
    private_use: self.private_use.copy(),
  }
}

///|
pub fn TagBuilder::with_region(
  self : TagBuilder,
  region : String,
) -> TagBuilder {
  {
    language: self.language,
    extlang: self.extlang.copy(),
    script: self.script,
    region,
    variants: self.variants.copy(),
    extensions: self.extensions.copy(),
    private_use: self.private_use.copy(),
  }
}

///|
pub fn TagBuilder::with_variant(
  self : TagBuilder,
  variant : String,
) -> TagBuilder {
  let next = self.variants.copy()
  next.push(variant)
  {
    language: self.language,
    extlang: self.extlang.copy(),
    script: self.script,
    region: self.region,
    variants: next,
    extensions: self.extensions.copy(),
    private_use: self.private_use.copy(),
  }
}

///|
pub fn TagBuilder::with_extension(
  self : TagBuilder,
  singleton : String,
  parts : Array[String],
) -> TagBuilder {
  let next = self.extensions.copy()
  next.push({ singleton, parts: parts.copy() })
  {
    language: self.language,
    extlang: self.extlang.copy(),
    script: self.script,
    region: self.region,
    variants: self.variants.copy(),
    extensions: next,
    private_use: self.private_use.copy(),
  }
}

///|
pub fn TagBuilder::with_private_use(
  self : TagBuilder,
  part : String,
) -> TagBuilder {
  let next = self.private_use.copy()
  next.push(part)
  {
    language: self.language,
    extlang: self.extlang.copy(),
    script: self.script,
    region: self.region,
    variants: self.variants.copy(),
    extensions: self.extensions.copy(),
    private_use: next,
  }
}

///|
pub fn TagBuilder::build(
  self : TagBuilder,
) -> (LanguageTag?, Array[Diagnostic]) {
  parse_with_diagnostics(
    format({
      kind: Regular,
      language: self.language,
      extlang: self.extlang,
      script: self.script,
      region: self.region,
      variants: self.variants,
      extensions: self.extensions,
      private_use: self.private_use,
      grandfathered: "",
    }),
  )
}

///|
pub fn TagBuilder::build_canonical(
  self : TagBuilder,
) -> (LanguageTag?, Array[Diagnostic]) {
  let (tag, diags) = self.build()
  match tag {
    None => (None, diags)
    Some(t) => (Some(canonicalize(t)), diags)
  }
}