///|
pub struct DeliveryStatus {
  final_recipient : String
  action : String
  status : String
  diagnostic_code : String
  remote_mta : String
} derive(Eq, Debug)

///|
pub fn delivery_statuses(message : MailMessage) -> Array[DeliveryStatus] {
  let out : Array[DeliveryStatus] = []
  for part in flatten_parts(message) {
    if part.content_type.media_type == "message" &&
      part.content_type.subtype == "delivery-status" {
      for item in parse_delivery_status_body(part_body_text(part)) {
        out.push(item)
      }
    }
  }
  out
}

///|
pub fn parse_delivery_status_body(body : String) -> Array[DeliveryStatus] {
  let blocks = split_status_blocks(body)
  let out : Array[DeliveryStatus] = []
  for block in blocks {
    let headers = parse_header_block(block)
    let final_recipient = header_value(headers, "Final-Recipient")
    if final_recipient != "" {
      out.push({
        final_recipient,
        action: header_value(headers, "Action"),
        status: header_value(headers, "Status"),
        diagnostic_code: header_value(headers, "Diagnostic-Code"),
        remote_mta: header_value(headers, "Remote-MTA"),
      })
    }
  }
  out
}

///|
fn split_status_blocks(body : String) -> Array[String] {
  let lines = split_lines(body)
  let blocks : Array[String] = []
  let mut current = ""
  for line in lines {
    if line == "" {
      if current != "" {
        blocks.push(current)
        current = ""
      }
    } else {
      current = current + line + "\n"
    }
  }
  if current != "" {
    blocks.push(current)
  }
  blocks
}

///|
pub fn is_bounce(message : MailMessage) -> Bool {
  lower_ascii(header_value(message.headers, "Auto-Submitted")) == "auto-replied" ||
  delivery_statuses(message).length() > 0 ||
  content_summary(message).contains("delivery")
}

///|
pub fn failed_recipient_count(message : MailMessage) -> Int {
  let mut count = 0
  for status in delivery_statuses(message) {
    if lower_ascii(status.action) == "failed" {
      count = count + 1
    }
  }
  count
}

///|
pub fn dsn_summary(message : MailMessage) -> String {
  let mut out = ""
  for status in delivery_statuses(message) {
    if out != "" {
      out = out + "\n"
    }
    out = out +
      status.final_recipient +
      " " +
      status.action +
      " " +
      status.status
  }
  out
}

///|
fn part_body_text(part : MailPart) -> String {
  if part.decoded_body != "" {
    part.decoded_body
  } else {
    part.raw_body
  }
}

///|
fn content_summary(message : MailMessage) -> String {
  lower_ascii(
    message.subject +
    " " +
    plain_text(message) +
    " " +
    strip_html(html_text(message)),
  )
}