function asRecord(value: unknown): Record<string, unknown> {
  return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
}

function asArray(value: unknown): unknown[] {
  return Array.isArray(value) ? value : [];
}

export type MailboxAddress = {
  name?: string;
  email: string;
};

export function normalizeEmailAddress(address: MailboxAddress): MailboxAddress {
  return {
    name: (address.name ?? "").trim(),
    email: (address.email ?? "").trim().toLowerCase()
  };
}

export function isValidEmailAddress(email: string): boolean {
  const normalized = email.trim();
  if (!normalized || normalized.length > 254) return false;
  return /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(normalized);
}

export function addressFromRecord(value: unknown): MailboxAddress | null {
  const record = asRecord(value);
  const email = typeof record.email === "string" ? record.email.trim() : "";
  if (!email) return null;
  const name = typeof record.name === "string" ? record.name.trim() : "";
  return normalizeEmailAddress({ name, email });
}

export function addressesFromValue(value: unknown): MailboxAddress[] {
  if (Array.isArray(value)) {
    return value.map(addressFromRecord).filter((item): item is MailboxAddress => Boolean(item));
  }
  const single = addressFromRecord(value);
  return single ? [single] : [];
}


export function parseMailboxAddressText(input: string): MailboxAddress | null {
  const text = input.trim().replace(/[;,]+$/g, "");
  if (!text) return null;

  const angleMatch = text.match(/^(.+?)\s*<\s*([^<>\s]+@[^<>\s]+)\s*>$/);
  if (angleMatch) {
    return normalizeEmailAddress({ name: cleanAddressName(angleMatch[1]), email: angleMatch[2] });
  }

  const emailMatch = text.match(/([^\s<>;,]+@[^\s<>;,]+\.[^\s<>;,]+)/);
  if (!emailMatch) return null;

  const email = emailMatch[1];
  const name = cleanAddressName(`${text.slice(0, emailMatch.index)} ${text.slice((emailMatch.index ?? 0) + email.length)}`);
  return normalizeEmailAddress({ name, email });
}

function cleanAddressName(value: string): string {
  return value
    .trim()
    .replace(/[<>]/g, "")
    .replace(/^[\s"'`]+|[\s"'`]+$/g, "")
    .replace(/[;,]+$/g, "")
    .trim();
}

export function collectCampaignAddressSuggestions(draft: Record<string, unknown> | null | undefined): MailboxAddress[] {
  if (!draft) return [];
  const suggestions: MailboxAddress[] = [];
  const recipients = asRecord(draft.recipients);
  const sender = addressFromRecord(recipients.from);
  if (sender) suggestions.push(sender);
  for (const key of ["to", "cc", "bcc", "reply_to", "bounce_to", "disposition_notification_to"]) {
    suggestions.push(...addressesFromValue(recipients[key]));
  }

  const entries = asRecord(draft.entries);
  for (const entryValue of asArray(entries.inline)) {
    const entry = asRecord(entryValue);
    const toAddresses = asArray(entry.to).map(addressFromRecord).filter((item): item is MailboxAddress => Boolean(item));
    suggestions.push(...toAddresses);
    const direct = addressFromRecord(entry.recipient) ?? addressFromRecord(entry);
    if (direct) suggestions.push(direct);
  }

  return dedupeAddresses(suggestions);
}

export function dedupeAddresses(addresses: MailboxAddress[]): MailboxAddress[] {
  const seen = new Map<string, MailboxAddress>();
  addresses.map(normalizeEmailAddress).forEach((address) => {
    if (!address.email) return;
    const existing = seen.get(address.email);
    if (!existing || (!existing.name && address.name)) {
      seen.set(address.email, address);
    }
  });
  return [...seen.values()].sort((left, right) => (left.name || left.email).localeCompare(right.name || right.email));
}

export function addressDisplayName(address: MailboxAddress): string {
  const normalized = normalizeEmailAddress(address);
  return normalized.name || normalized.email;
}
