/**
 * Email identity rules.
 *
 * `normaliseEmail` produces the uniqueness key stored in `users.email_key`. The
 * point is that the obvious ways of turning one inbox into many accounts —
 * `me+1@`, `me+2@`, or Gmail's ignored dots — all collapse onto the same key,
 * so the unique index rejects the second signup.
 *
 * Trade-off worth knowing: a handful of providers do treat `+tags` as separate
 * real mailboxes. Set `STRIP_PLUS_TAGS_EVERYWHERE` to false to limit the
 * aliasing rules to Gmail only if that ever bites a legitimate user.
 */

const STRIP_PLUS_TAGS_EVERYWHERE = true;

/** Providers where dots in the local part are cosmetic. */
const DOT_INSENSITIVE_DOMAINS = new Set(["gmail.com", "googlemail.com"]);

const DOMAIN_ALIASES: Record<string, string> = {
  "googlemail.com": "gmail.com",
};

/**
 * Known throw-away mailbox providers. Deliberately short and high-signal —
 * an exhaustive list is a losing race, this only blocks the lazy path. Extend
 * it (or swap in a maintained list) if abuse shows up from elsewhere.
 */
const DISPOSABLE_DOMAINS = new Set([
  "10minutemail.com",
  "20minutemail.com",
  "discard.email",
  "dispostable.com",
  "fakeinbox.com",
  "getairmail.com",
  "guerrillamail.com",
  "guerrillamail.info",
  "mailinator.com",
  "maildrop.cc",
  "mailnesia.com",
  "mintemail.com",
  "mohmal.com",
  "sharklasers.com",
  "spam4.me",
  "temp-mail.org",
  "tempmail.com",
  "tempmailo.com",
  "throwawaymail.com",
  "trashmail.com",
  "yopmail.com",
  "yopmail.net",
]);

export function splitEmail(raw: string): { local: string; domain: string } | null {
  const trimmed = raw.trim().toLowerCase();
  const atIndex = trimmed.lastIndexOf("@");
  if (atIndex <= 0 || atIndex === trimmed.length - 1) return null;

  const local = trimmed.slice(0, atIndex);
  const domain = trimmed.slice(atIndex + 1);
  if (!local || !domain.includes(".")) return null;

  return { local, domain };
}

/** Lower-cased address as typed, minus surrounding whitespace. For display and delivery. */
export function canonicaliseEmail(raw: string): string {
  return raw.trim().toLowerCase();
}

/** Aliasing-resistant key used for the uniqueness constraint. */
export function normaliseEmail(raw: string): string | null {
  const parts = splitEmail(raw);
  if (!parts) return null;

  const domain = DOMAIN_ALIASES[parts.domain] ?? parts.domain;
  let local = parts.local;

  if (STRIP_PLUS_TAGS_EVERYWHERE || DOT_INSENSITIVE_DOMAINS.has(domain)) {
    const plusIndex = local.indexOf("+");
    if (plusIndex > 0) local = local.slice(0, plusIndex);
  }

  if (DOT_INSENSITIVE_DOMAINS.has(domain)) {
    local = local.replace(/\./g, "");
  }

  if (!local) return null;
  return `${local}@${domain}`;
}

export function isDisposableEmail(raw: string): boolean {
  const parts = splitEmail(raw);
  if (!parts) return false;
  const domain = DOMAIN_ALIASES[parts.domain] ?? parts.domain;
  return DISPOSABLE_DOMAINS.has(domain);
}
