import type { Recipient } from "@/lib/api/types"
import { cleanSenderName } from "@/lib/sender-display"

export function normalizeMailAddress(addr: string): string {
  return addr.trim().toLowerCase().replace(/^<|>$/g, "")
}

function parseAngleAddr(value: string): { name: string; email: string } {
  const trimmed = value.trim()
  const match = trimmed.match(/^(.*?)\s*<([^>]+)>$/)
  if (match) {
    return {
      name: match[1]?.trim() ?? "",
      email: match[2]?.trim() ?? "",
    }
  }
  if (trimmed.includes("@") && !trimmed.includes(" ")) {
    return { name: "", email: trimmed.replace(/^<|>$/g, "") }
  }
  return { name: trimmed, email: "" }
}

/** Normalizes API from[] when IMAP/sync left name or address empty or combined. */
export function resolveMessageFrom(
  from: Recipient[] | undefined,
  options?: {
    selfEmails?: Iterable<string>
    selfDisplayName?: string
  }
): { name: string; email: string } {
  const first = from?.[0]
  let name = first?.name?.trim() ?? ""
  let email = first?.address?.trim() ?? ""

  if (!email && name) {
    const parsed = parseAngleAddr(name)
    name = parsed.name
    email = parsed.email
  }
  if (!name && email) {
    const parsed = parseAngleAddr(email)
    if (parsed.email) {
      email = parsed.email
      name = parsed.name
    }
  }

  email = email.replace(/^<|>$/g, "")
  const selfSet = new Set(
    options?.selfEmails
      ? [...options.selfEmails].map(normalizeMailAddress).filter(Boolean)
      : []
  )

  if (email && selfSet.has(normalizeMailAddress(email)) && options?.selfDisplayName) {
    name = options.selfDisplayName
  } else if (email && !name) {
    const local = email.split("@")[0] ?? email
    name = local.replace(/[._-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
  }

  return {
    name: cleanSenderName(name || email),
    email,
  }
}

export function collectSelfMailEmails(
  accounts: { email: string }[] | undefined,
  identities: { email: string }[] | undefined,
  platformEmail?: string | null
): string[] {
  const out = new Set<string>()
  for (const a of accounts ?? []) {
    if (a.email) out.add(normalizeMailAddress(a.email))
  }
  for (const i of identities ?? []) {
    if (i.email) out.add(normalizeMailAddress(i.email))
  }
  if (platformEmail) out.add(normalizeMailAddress(platformEmail))
  return [...out]
}

export function isMessageFromSelf(
  from: Recipient[] | undefined,
  selfEmails: Iterable<string>
): boolean {
  const { email } = resolveMessageFrom(from)
  if (!email) return false
  const norm = normalizeMailAddress(email)
  for (const s of selfEmails) {
    if (norm === normalizeMailAddress(s)) return true
  }
  return false
}

function recipientDisplayName(r: Recipient): string {
  const name = r.name?.trim()
  if (name) return cleanSenderName(name)
  const addr = r.address?.trim().replace(/^<|>$/g, "")
  if (!addr) return ""
  const local = addr.split("@")[0] ?? addr
  return cleanSenderName(
    local.replace(/[._-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
  )
}

const RECIPIENT_SUMMARY_NAMES = 3

function selfAddressSet(selfEmails: Iterable<string>): Set<string> {
  return new Set([...selfEmails].map(normalizeMailAddress).filter(Boolean))
}

/** To/Cc rows that match one of the user's mail addresses. */
export function selfRecipientsInMessage(
  to: Recipient[] | undefined,
  cc: Recipient[] | undefined,
  selfEmails: Iterable<string>
): Recipient[] {
  const self = selfAddressSet(selfEmails)
  const seen = new Set<string>()
  const out: Recipient[] = []
  for (const r of [...(to ?? []), ...(cc ?? [])]) {
    if (!r.address) continue
    const norm = normalizeMailAddress(r.address)
    if (!self.has(norm) || seen.has(norm)) continue
    seen.add(norm)
    out.push(r)
  }
  return out
}

/** External recipients (excludes self addresses). */
export function externalRecipients(
  to: Recipient[] | undefined,
  cc: Recipient[] | undefined,
  selfEmails: Iterable<string>
): Recipient[] {
  const self = selfAddressSet(selfEmails)
  return [...(to ?? []), ...(cc ?? [])].filter(
    (r) => r.address && !self.has(normalizeMailAddress(r.address))
  )
}

/** "moi" with the mailbox that received/sent (Gmail-style precision). */
export function formatSelfMoiLabel(r: Recipient): string {
  const email = r.address?.trim().replace(/^<|>$/g, "")
  return email ? `moi <${email}>` : "moi"
}

/** Gmail-style one-line: à moi | à Name | à A, B, C + N autres */
export function formatMessageToSummary(
  to: Recipient[] | undefined,
  cc: Recipient[] | undefined,
  selfEmails: Iterable<string>
): string {
  const recipients = externalRecipients(to, cc, selfEmails)
  const selfOnly = selfRecipientsInMessage(to, cc, selfEmails)

  if (recipients.length === 0) {
    if (selfOnly.length === 1) {
      return `à ${formatSelfMoiLabel(selfOnly[0]!)}`
    }
    if (selfOnly.length > 1) {
      return `à ${selfOnly.map(formatSelfMoiLabel).join(", ")}`
    }
    return "à moi"
  }
  if (recipients.length === 1) {
    const label = recipientDisplayName(recipients[0]!)
    return label ? `à ${label}` : "à moi"
  }
  if (recipients.length <= RECIPIENT_SUMMARY_NAMES) {
    return `à ${recipients.map((r) => recipientDisplayName(r)).join(", ")}`
  }
  const shown = recipients
    .slice(0, RECIPIENT_SUMMARY_NAMES)
    .map((r) => recipientDisplayName(r))
    .join(", ")
  const rest = recipients.length - RECIPIENT_SUMMARY_NAMES
  return `à ${shown} + ${rest} autre${rest > 1 ? "s" : ""}`
}

export function formatRecipientMailbox(r: Recipient): string {
  const { name, email } = resolveMessageFrom([r])
  if (name && email) return `${name} <${email}>`
  return email || name
}

/** All To/Cc including self, for the details popover. */
export function formatAllRecipientsLine(
  to: Recipient[] | undefined,
  cc: Recipient[] | undefined,
  selfEmails: Iterable<string>
): string {
  const self = new Set([...selfEmails].map(normalizeMailAddress).filter(Boolean))
  const parts: string[] = []
  for (const r of to ?? []) {
    if (!r.address) continue
    if (self.has(normalizeMailAddress(r.address))) {
      parts.push(formatSelfMoiLabel(r))
    } else {
      parts.push(formatRecipientMailbox(r))
    }
  }
  for (const r of cc ?? []) {
    if (!r.address) continue
    const box = formatRecipientMailbox(r)
    parts.push(parts.length ? `Cc: ${box}` : box)
  }
  if (parts.length > 0) return parts.join(", ")
  const selfOnly = selfRecipientsInMessage(to, cc, selfEmails)
  if (selfOnly[0]) return formatSelfMoiLabel(selfOnly[0])
  return "moi"
}
