///|
pub(all) enum MailCategory {
  Personal
  Newsletter
  Notification
  Security
  Billing
  BuildSystem
  CalendarInvite
  Bounce
  UnknownCategory
} derive(Eq, Debug)

///|
pub fn classify_message(message : MailMessage) -> MailCategory {
  let subject = lower_ascii(message.subject)
  let from = lower_ascii(join_mailboxes_for_classification(message.from))
  let body = lower_ascii(
    plain_text(message) + " " + strip_html(html_text(message)),
  )
  if is_bounce(message) {
    Bounce
  } else if subject.contains("invoice") || from.contains("billing") {
    Billing
  } else if subject.contains("password") ||
    from.contains("security") ||
    body.contains("reset your password") {
    Security
  } else if subject.contains("build failed") || from.contains("ci@") {
    BuildSystem
  } else if from.contains("newsletter") || has_list_unsubscribe(message) {
    Newsletter
  } else if from.contains("calendar") ||
    has_attachment_named(message, "invite.ics") {
    CalendarInvite
  } else if from.contains("support") || subject.contains("ticket") {
    Notification
  } else if message.from.length() > 0 &&
    (message.to.length() > 0 || message.cc.length() > 0) {
    Personal
  } else {
    UnknownCategory
  }
}

///|
fn join_mailboxes_for_classification(items : Array[Address]) -> String {
  let mut out = ""
  for item in items {
    out = out + " " + item.display + " " + item.mailbox
  }
  out
}

///|
pub fn category_name(category : MailCategory) -> String {
  match category {
    Personal => "personal"
    Newsletter => "newsletter"
    Notification => "notification"
    Security => "security"
    Billing => "billing"
    BuildSystem => "build-system"
    CalendarInvite => "calendar-invite"
    Bounce => "bounce"
    UnknownCategory => "unknown"
  }
}

///|
pub fn category_counts(messages : Array[MailMessage]) -> Array[(String, Int)] {
  let names = [
    "personal", "newsletter", "notification", "security", "billing", "build-system",
    "calendar-invite", "bounce", "unknown",
  ]
  let out : Array[(String, Int)] = []
  for name in names {
    let mut count = 0
    for message in messages {
      if category_name(classify_message(message)) == name {
        count = count + 1
      }
    }
    out.push((name, count))
  }
  out
}

///|
pub fn messages_by_category(
  messages : Array[MailMessage],
  category : MailCategory,
) -> Array[MailMessage] {
  let out : Array[MailMessage] = []
  for message in messages {
    if classify_message(message) == category {
      out.push(message)
    }
  }
  out
}