// header.mbt
// A Header represents the key-value pairs in an HTTP header.
// Keys are stored in canonical form (similar to net/http CanonicalHeaderKey).

///|
pub struct Header(Map[String, Array[String]])

///|
pub fn new() -> Header {
  Header(Map([]))
}

// CanonicalHeaderKey: roughly mimics Go's textproto.CanonicalMIMEHeaderKey.
// Rules:
// - Split by '-'.
// - For each token: first letter uppercase, rest lowercase.
// - Keep other characters as-is.

///|
pub fn canonicalHeaderKey(key : String) -> String {
  if key == "" {
    return ""
  }

  // Lowercase first, then Title-Case by '-' tokens.
  let lower = key.to_lower()
  let parts = lower.split("-")
  let out_parts : Array[String] = []
  for p in parts {
    if p == "" {
      out_parts.push("")
    } else {
      // upper first char, keep rest
      guard p is [first, .. rest]
      out_parts.push(first.to_string().to_upper() + rest.to_owned())
    }
  }
  out_parts.join("-")
}

// Add adds the key, value pair to the header.
// It appends to any existing values associated with key.
// The key is case insensitive; it is canonicalized.

///|
pub fn Header::add(h : Header, key : String, value : String) -> Unit {
  let k = canonicalHeaderKey(key)
  let Header(m) = h
  m.get_or_init(k, () => []).push(value)
}

// Set sets the header entries associated with key to the single element value.
// It replaces any existing values associated with key.
// The key is case insensitive; it is canonicalized.

///|
pub fn Header::set(h : Header, key : String, value : String) -> Unit {
  let k = canonicalHeaderKey(key)
  let Header(m) = h
  let arr = m.get_or_init(k, () => [])
  arr.drain(0, arr.length()).push(value)
}

// Get gets the first value associated with the given key.
// If there are no values, returns "".
// The key is case insensitive; it is canonicalized.

///|
pub fn Header::get(h : Header, key : String) -> String? {
  let k = canonicalHeaderKey(key)
  let Header(m) = h
  match m.get(k) {
    Some(vv) if vv.length() > 0 => Some(vv[0])
    _ => None
  }
}

// Values returns all values associated with the given key.
// If none, returns empty array.
// The key is case insensitive; it is canonicalized.
// NOTE: returns a copy for safety.

///|
pub fn Header::values(h : Header, key : String) -> Array[String] {
  let k = canonicalHeaderKey(key)
  let Header(m) = h
  match m.get(k) {
    Some(vv) => vv.copy()
    None => []
  }
}

// has reports whether h has the provided key defined.

///|
pub fn Header::has(h : Header, key : String) -> Bool {
  let k = canonicalHeaderKey(key)
  h.get(k) is Some(_)
}

// del deletes the values associated with key.
// The key is case insensitive; it is canonicalized.

///|
pub fn Header::del(h : Header, key : String) -> Unit {
  let k = canonicalHeaderKey(key)
  let Header(m) = h
  m.remove(k)
}

// Clone returns a deep copy of h.
// In Go, Header.Clone preserves nil vs empty slices; MoonBit version does not.

///|
pub fn Header::copy(h : Header) -> Header {
  let h2 = Map([], capacity=h.0.length())
  for k, vv in h.0 {
    h2.set(k, vv.copy())
  }
  h2
}