export type MailboxSpamLanguage = "en" | "ja" | "ru" | "zh";

type DetectedMailboxLanguage = MailboxSpamLanguage | "ko";

export const MAILBOX_SPAM_LANGUAGES = ["en", "ja", "ru", "zh"] as const satisfies readonly MailboxSpamLanguage[];

export function normalizeMailboxSpamLanguages(value: unknown): MailboxSpamLanguage[] {
  const source = Array.isArray(value) ? value : String(value ?? "").split(",");
  return [...new Set(source.map((item) => String(item).trim().toLowerCase()))]
    .filter((item): item is MailboxSpamLanguage => MAILBOX_SPAM_LANGUAGES.includes(item as MailboxSpamLanguage));
}

function detectDominantMailboxLanguage(value: string, minimumCharacters: number): DetectedMailboxLanguage | null {
  const text = value
    .replace(/https?:\/\/\S+|www\.\S+/gi, " ")
    .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, " ")
    .slice(0, 12_000);
  const counts = { cyrillic: 0, han: 0, hangul: 0, kana: 0, latin: 0 };

  for (const character of text) {
    const codePoint = character.codePointAt(0) ?? 0;
    if ((codePoint >= 0xac00 && codePoint <= 0xd7af) || (codePoint >= 0x1100 && codePoint <= 0x11ff) || (codePoint >= 0x3130 && codePoint <= 0x318f)) {
      counts.hangul += 1;
    } else if ((codePoint >= 0x3040 && codePoint <= 0x30ff) || (codePoint >= 0x31f0 && codePoint <= 0x31ff)) {
      counts.kana += 1;
    } else if ((codePoint >= 0x3400 && codePoint <= 0x4dbf) || (codePoint >= 0x4e00 && codePoint <= 0x9fff)) {
      counts.han += 1;
    } else if (codePoint >= 0x0400 && codePoint <= 0x052f) {
      counts.cyrillic += 1;
    } else if ((codePoint >= 0x0041 && codePoint <= 0x005a) || (codePoint >= 0x0061 && codePoint <= 0x007a)) {
      counts.latin += 1;
    }
  }

  const total = counts.hangul + counts.kana + counts.han + counts.cyrillic + counts.latin;
  if (total < minimumCharacters) return null;

  const scores: Record<DetectedMailboxLanguage, number> = {
    en: counts.latin,
    ja: counts.kana >= 3 ? counts.kana + counts.han : 0,
    ko: counts.hangul,
    ru: counts.cyrillic,
    zh: counts.kana < 3 ? counts.han : 0
  };
  const [dominant] = (Object.entries(scores) as Array<[DetectedMailboxLanguage, number]>)
    .sort((left, right) => right[1] - left[1]);

  if (!dominant || dominant[1] < minimumCharacters || dominant[1] / total < 0.6) return null;
  return dominant[0];
}

export function detectMailboxSpamLanguage(subject: string, bodyText: string): MailboxSpamLanguage | null {
  const subjectLanguage = detectDominantMailboxLanguage(subject, 4);
  const bodyLanguage = detectDominantMailboxLanguage(bodyText, 20);

  if (!bodyLanguage) return null;
  if (subjectLanguage && bodyLanguage && subjectLanguage !== bodyLanguage) return null;
  return bodyLanguage !== "ko" ? bodyLanguage : null;
}
