///|
/// MIME multipart subtype.
pub(all) enum MimeSubtype {
  Mixed
  Alternative
  Related
} derive(Eq, Debug)

///|
pub fn MimeSubtype::to_string(self : MimeSubtype) -> String {
  match self {
    Mixed => "mixed"
    Alternative => "alternative"
    Related => "related"
  }
}

///|
pub impl Show for MimeSubtype with fn output(self, logger) {
  logger.write_string(self.to_string())
}

///|
/// The body of a message or part.
pub(all) enum MimeBody {
  /// Plain text content (UTF-8).
  Text(String)
  /// HTML content (UTF-8).
  Html(String)
  /// Raw binary payload plus its original filename.
  Binary(Bytes, String)
  /// A nested multipart container.
  MultiPart(Array[Part], MimeSubtype)
} derive(Eq, Debug)

///|
/// A single MIME part: its own headers plus a body.
pub struct Part {
  headers : Array[(String, String)]
  body : MimeBody
} derive(Eq, Debug)

///|
pub fn Part::new() -> Part {
  { headers: [], body: Text("") }
}

///|
pub fn Part::body(self : Part) -> MimeBody {
  self.body
}

///|
pub fn Part::headers(self : Part) -> Array[(String, String)] {
  self.headers
}

///|
/// Find the first header value for `name` (case-insensitive), or `None`.
pub fn Part::header(self : Part, name : String) -> String? {
  get_header(self.headers, name)
}

///|
pub fn Part::set_header(self : Part, name : String, value : String) -> Unit {
  set_header(self.headers, name, value)
}

///|
pub fn Part::add_header(self : Part, name : String, value : String) -> Unit {
  self.headers.push((name, value))
}

///|
/// A parsed email message: header fields plus a MIME body tree.
pub struct MailMessage {
  headers : Array[(String, String)]
  body : MimeBody
} derive(Eq, Debug)

///|
pub fn MailMessage::new(body : MimeBody) -> MailMessage {
  { headers: [], body }
}

///|
pub fn MailMessage::body(self : MailMessage) -> MimeBody {
  self.body
}

///|
pub fn MailMessage::headers(self : MailMessage) -> Array[(String, String)] {
  self.headers
}

///|
/// Find the first header value for `name` (case-insensitive), or `None`.
pub fn MailMessage::header(self : MailMessage, name : String) -> String? {
  get_header(self.headers, name)
}

///|
/// Set (replacing any existing) header `name`.
pub fn MailMessage::set_header(
  self : MailMessage,
  name : String,
  value : String,
) -> Unit {
  set_header(self.headers, name, value)
}

///|
pub fn MailMessage::add_header(
  self : MailMessage,
  name : String,
  value : String,
) -> Unit {
  self.headers.push((name, value))
}

///|
/// Get a header value, matching the name case-insensitively (RFC 5322 2.2).
fn get_header(headers : Array[(String, String)], name : String) -> String? {
  for pair in headers {
    let (n, v) = pair
    if n.to_lower() == name.to_lower() {
      return Some(v)
    }
  }
  None
}

///|
/// Replace an existing header value or append a new one.
fn set_header(
  headers : Array[(String, String)],
  name : String,
  value : String,
) -> Unit {
  for i = 0; i < headers.length(); i = i + 1 {
    let (n, _) = headers[i]
    if n.to_lower() == name.to_lower() {
      headers[i] = (name, value)
      return
    }
  }
  headers.push((name, value))
}