///|
/// Content-Language header parsing errors (RFC 9110 Section 8.5)
pub(all) enum ContentLanguageError {
  Empty
  InvalidFormat
  InvalidLanguageTag
} derive(Show, Eq)

///|
/// Content-Language header (RFC 9110 Section 8.5)
pub(all) struct ContentLanguage {
  tags : Array[String]
} derive(Eq)

///|
pub fn ContentLanguage::parse(
  input : String,
) -> Result[ContentLanguage, ContentLanguageError] {
  let s = cl_trim_string(input)
  if s.length() == 0 {
    return Err(Empty)
  }
  let parts = cl_split_string(s, ",")
  let tags : Array[String] = []
  let mut part_idx = 0
  while part_idx < parts.length() {
    let tag = cl_trim_string(parts[part_idx])
    if tag.length() > 0 {
      if !cl_is_valid_language_tag(tag) {
        return Err(InvalidLanguageTag)
      }
      tags.push(tag)
    }
    part_idx = part_idx + 1
  }
  if tags.length() == 0 {
    return Err(Empty)
  }
  Ok({ tags, })
}

///|
pub fn ContentLanguage::tags(self : ContentLanguage) -> Array[String] {
  self.tags
}

///|
pub fn ContentLanguage::to_string(self : ContentLanguage) -> String {
  cl_join_strings(self.tags, ", ")
}

///|
/// Helper functions
///

///|
fn cl_is_valid_language_tag(tag : String) -> Bool {
  if tag.length() == 0 {
    return false
  }

  // Split by '-' and validate each part
  let parts = cl_split_string(tag, "-")
  let mut has_part = false
  let mut idx = 0
  while idx < parts.length() {
    let part = parts[idx]
    has_part = true
    if part.length() == 0 || part.length() > 8 {
      return false
    }
    // Check alphanumeric
    let mut ch_idx = 0
    while ch_idx < part.length() {
      let ch = cl_char_at(part, ch_idx)
      if !cl_is_alnum(ch) {
        return false
      }
      ch_idx = ch_idx + 1
    }
    idx = idx + 1
  }
  has_part
}

///|
fn cl_is_alnum(b : Int) -> Bool {
  (b >= 48 && b <= 57) || // 0-9
  (b >= 65 && b <= 90) || // A-Z
  (b >= 97 && b <= 122) // a-z
}

///|
fn cl_char_at(s : String, idx : Int) -> Int {
  str_char_at(s, idx)
}

///|
fn cl_trim_string(s : String) -> String {
  str_trim_string(s)
}

///|
fn cl_split_string(s : String, sep : String) -> Array[String] {
  str_split_string(s, sep)
}

///|
fn cl_join_strings(strs : Array[String], sep : String) -> String {
  let mut result = ""
  let mut idx = 0
  while idx < strs.length() {
    if idx > 0 {
      result = result + sep
    }
    result = result + strs[idx]
    idx = idx + 1
  }
  result
}