// DKIM 规范化(RFC 6376 3.4)。
//
// simple 保留原字节,relaxed 做小写、折叠压缩与行尾空白清理;
// body 两种模式都要处理「末尾空行」与「缺少结尾 CRLF」。

///|
pub enum CanonMode {
  Simple
  Relaxed
}

///|
fn is_wsp_byte(b : Byte) -> Bool {
  b == b' ' || b == b'\t'
}

///|
/// 规范化一个头部字段,输出总是以 CRLF 结尾。
pub fn canonicalize_header(field : HeaderField, mode : CanonMode) -> Bytes {
  match mode {
    Simple => {
      let out : Array[Byte] = []
      for b in field.raw {
        out.push(b)
      }
      out.push(b'\r')
      out.push(b'\n')
      Bytes::from_array(out)
    }
    Relaxed => {
      let raw = field.raw
      let n = raw.length()
      let mut colon = 0
      while colon < n && raw[colon] != b':' {
        colon = colon + 1
      }
      let out : Array[Byte] = []
      // 字段名:去掉尾部 WSP 并转小写
      let mut name_end = colon
      while name_end > 0 && is_wsp_byte(raw[name_end - 1]) {
        name_end = name_end - 1
      }
      for i in 0..= b'A' && b <= b'Z' {
          out.push((b.to_uint() + 32U).to_byte())
        } else {
          out.push(b)
        }
      }
      out.push(b':')
      // 值:展开折叠、压缩 WSP、去掉首尾 WSP
      let value = collect_relaxed_value(
        raw,
        if colon < n {
          colon + 1
        } else {
          n
        },
      )
      for b in value {
        out.push(b)
      }
      out.push(b'\r')
      out.push(b'\n')
      Bytes::from_array(out)
    }
  }
}

///|
/// 收集 relaxed 头部值:CRLF 折叠变成单个 SP,WSP 序列压缩成一个 SP。
fn collect_relaxed_value(raw : Bytes, start : Int) -> Array[Byte] {
  let out : Array[Byte] = []
  let n = raw.length()
  let mut i = start
  let mut pending_wsp = false
  let mut wrote_any = false
  while i < n {
    let b = raw[i]
    if b == b'\r' || b == b'\n' {
      // 折叠边界
      pending_wsp = true
      i = i + 1
      continue
    }
    if is_wsp_byte(b) {
      pending_wsp = true
      i = i + 1
      continue
    }
    if pending_wsp && wrote_any {
      out.push(b' ')
    }
    pending_wsp = false
    out.push(b)
    wrote_any = true
    i = i + 1
  }
  out
}

///|
/// 规范化正文。
pub fn canonicalize_body(body : Bytes, mode : CanonMode) -> Bytes {
  let out : Array[Byte] = []
  match mode {
    Simple =>
      for b in body {
        out.push(b)
      }
    Relaxed => {
      let n = body.length()
      let mut pos = 0
      while pos < n {
        let line_start = pos
        let mut line_end = pos
        while line_end < n && body[line_end] != b'\n' {
          line_end = line_end + 1
        }
        let content_end = if line_end > line_start &&
          body[line_end - 1] == b'\r' {
          line_end - 1
        } else {
          line_end
        }
        // 行内压缩 WSP,去掉行尾 WSP
        let mut pending_wsp = false
        let mut wrote = false
        for i in line_start..= 4 &&
        out[end - 4] == b'\r' &&
        out[end - 3] == b'\n' &&
        out[end - 2] == b'\r' &&
        out[end - 1] == b'\n' {
    end = end - 2
  }
  if end == 0 {
    out.push(b'\r')
    out.push(b'\n')
  } else if end >= 2 && out[end - 2] == b'\r' && out[end - 1] == b'\n' {
    // 已经是单个 CRLF 结尾
  } else {
    out.push(b'\r')
    out.push(b'\n')
  }
  let result : Array[Byte] = []
  let final_len = if end == 0 {
    2
  } else if out[end - 1] == b'\n' {
    end
  } else {
    out.length()
  }
  for i in 0..