///|
pub struct Contact {
  display : String
  mailbox : String
  domain : String
} derive(Eq, Debug)

///|
pub fn contact_from_address(addr : Address) -> Contact {
  {
    display: addr.display,
    mailbox: addr.mailbox,
    domain: mailbox_domain(addr.mailbox),
  }
}

///|
pub fn message_contacts(message : MailMessage) -> Array[Contact] {
  let out : Array[Contact] = []
  for item in message.from {
    out.push(contact_from_address(item))
  }
  for item in message.to {
    out.push(contact_from_address(item))
  }
  for item in message.cc {
    out.push(contact_from_address(item))
  }
  out
}

///|
pub fn mailbox_domain(mailbox : String) -> String {
  match split_once(mailbox, '@') {
    Some((_, domain)) => lower_ascii(trim_ascii(domain))
    None => ""
  }
}

///|
pub fn sender_domain(message : MailMessage) -> String {
  if message.from.length() > 0 {
    mailbox_domain(message.from[0].mailbox)
  } else {
    ""
  }
}

///|
pub fn recipient_domains(message : MailMessage) -> Array[String] {
  let out : Array[String] = []
  for item in message.to {
    push_unique(out, mailbox_domain(item.mailbox))
  }
  for item in message.cc {
    push_unique(out, mailbox_domain(item.mailbox))
  }
  out
}

///|
fn push_unique(items : Array[String], value : String) -> Unit {
  if value == "" {
    return
  }
  for item in items {
    if item == value {
      return
    }
  }
  items.push(value)
}

///|
pub fn all_domains(messages : Array[MailMessage]) -> Array[String] {
  let out : Array[String] = []
  for message in messages {
    push_unique(out, sender_domain(message))
    for domain in recipient_domains(message) {
      push_unique(out, domain)
    }
  }
  out
}

///|
pub fn messages_from_domain(
  messages : Array[MailMessage],
  domain : String,
) -> Array[MailMessage] {
  let out : Array[MailMessage] = []
  let target = lower_ascii(domain)
  for message in messages {
    if sender_domain(message) == target {
      out.push(message)
    }
  }
  out
}