///|
/// Return whether a string is a legacy OpenMetrics metric identifier.
///
/// This intentionally accepts the interoperable ASCII form used by the
/// Prometheus/OpenMetrics text grammar:
/// `[A-Za-z_:][A-Za-z0-9_:]*`.
pub fn is_valid_metric_name(name : StringView) -> Bool {
  if name.is_empty() {
    return false
  }
  let mut first = true
  for char in name.iter() {
    if first {
      if !(char.is_ascii_alphabetic() || char == '_' || char == ':') {
        return false
      }
      first = false
    } else if !(char.is_ascii_alphabetic() ||
      char.is_ascii_digit() ||
      char == '_' ||
      char == ':') {
      return false
    }
  }
  true
}

///|
/// Return whether a string is a legacy OpenMetrics label identifier.
pub fn is_valid_label_name(name : StringView) -> Bool {
  if name.is_empty() {
    return false
  }
  let mut first = true
  for char in name.iter() {
    if first {
      if !(char.is_ascii_alphabetic() || char == '_') {
        return false
      }
      first = false
    } else if !(char.is_ascii_alphabetic() ||
      char.is_ascii_digit() ||
      char == '_') {
      return false
    }
  }
  true
}

///|
/// Escape a label value for a quoted OpenMetrics label string.
pub fn escape_label_value(value : StringView) -> String {
  let out = StringBuilder(size_hint=value.length())
  for char in value.iter() {
    match char {
      '\\' => out.write_string("\\\\")
      '"' => out.write_string("\\\"")
      '\n' => out.write_string("\\n")
      _ => out.write_char(char)
    }
  }
  out.to_string()
}

///|
/// Escape HELP text using the quoted-string escapes from OpenMetrics.
pub fn escape_help(value : StringView) -> String {
  let out = StringBuilder(size_hint=value.length())
  for char in value.iter() {
    match char {
      '\\' => out.write_string("\\\\")
      '"' => out.write_string("\\\"")
      '\n' => out.write_string("\\n")
      _ => out.write_char(char)
    }
  }
  out.to_string()
}

///|
fn unescape_text(
  value : StringView,
  allow_quote : Bool,
) -> Result[String, String] {
  let chars = value.to_array()
  let out = StringBuilder(size_hint=value.length())
  let mut i = 0
  while i < chars.length() {
    let char = chars[i]
    if char != '\\' {
      if char == '"' {
        return Err("unescaped quote in escaped text")
      }
      out.write_char(char)
      i += 1
      continue
    }
    if i + 1 >= chars.length() {
      return Err("trailing backslash in escaped text")
    }
    let escaped = chars[i + 1]
    match escaped {
      '\\' => out.write_char('\\')
      'n' => out.write_char('\n')
      '"' =>
        if allow_quote {
          out.write_char('"')
        } else {
          return Err("quote escape is not valid in HELP text")
        }
      _ => return Err("unsupported escape sequence \\\{escaped}")
    }
    i += 2
  }
  Ok(out.to_string())
}

///|
/// Decode the contents of a quoted label value.
pub fn unescape_label_value(value : StringView) -> Result[String, String] {
  unescape_text(value, true)
}

///|
/// Decode escaped HELP text.
pub fn unescape_help(value : StringView) -> Result[String, String] {
  unescape_text(value, true)
}