/**
 * Mail-Training-Utils — Phase 1 Data-Foundation.
 *
 * Zweck: Anonymisierung + Spracherkennung für zukünftiges ML-Training (Phase 3).
 * Diese Utilities bereiten Klassifikations-Samples so auf, dass sie DSGVO-konform
 * für Modell-Training verwendbar sind (Art. 5 Abs. 1e — Speicherbegrenzung).
 *
 * Scope dieser Datei:
 *   - sanitizeSubjectForTraining()  — PII-Stripping aus Betreff-Zeilen
 *   - detectSubjectLanguage()       — Spracherkennung via franc (iso639-3)
 *
 * Was hier NICHT ist:
 *   - ML-Inference / Modell-Calls (Phase 3)
 *   - NER (zu aufwendig für MVP)
 *   - Consent-Prüfung (liegt beim Aufrufer, nicht in dieser Util)
 *
 * DSGVO-Anmerkungen:
 *   - sanitizeSubjectForTraining() entfernt PII bevor Samples persistiert werden.
 *   - Raw-Subject bleibt 30 Tage in DB, danach via Retention-Cron auf null gesetzt.
 *   - detectedLang (iso639-3-Code) ist kein personenbezogenes Datum.
 */

// franc ist ein ESM-only package (v6+). Import funktioniert in Node ESM context.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore — franc hat keine @types, Exports sind sauber via JSDoc
import { franc } from "franc";

// ─── Typen ────────────────────────────────────────────────────────────────────

/**
 * Ergebnis der Sanitization.
 * subjectSanitized: PII-freie Version des Betreffs für ML-Training.
 * detectedLang: iso639-3-Code (z.B. "deu", "eng", "fra") oder "und" wenn unbekannt.
 */
export interface SubjectSanitizationResult {
  subjectSanitized: string;
  detectedLang: string;
}

// ─── Regex-Patterns für PII-Detection ────────────────────────────────────────

/**
 * Erkennt E-Mail-Adressen im Betreff.
 * Beispiel: "Info für test@example.com" → "Info für [EMAIL]"
 */
const RE_EMAIL = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g;

/**
 * Erkennt URLs (http/https/www-prefixed).
 * Beispiel: "Besuche https://casino.bet/promo" → "Besuche [URL]"
 */
const RE_URL = /(?:https?:\/\/|www\.)[^\s<>"'{}|\\^`\[\]]+/gi;

/**
 * Erkennt Zahlenfolgen mit mehr als 4 Ziffern (z.B. Kundennummern, Tracking-IDs).
 * 4-stellige Zahlen bleiben (Jahres-/Score-Angaben wie "2024", "1000€" bleiben lesbar).
 * Beispiel: "Bestellung 123456789" → "Bestellung [NUM]"
 */
const RE_LONG_NUMBER = /\b\d{5,}\b/g;

/**
 * Erkennt typische Grußformeln am Anfang des Betreffs.
 * Nach dem Grußwort + Komma folgt oft ein Name — alles bis zum nächsten
 * Satzzeichen/Trennzeichen wird als Personenreferenz behandelt und entfernt.
 *
 * Beispiele:
 *   "Hallo Max, dein Bonus wartet" → "dein Bonus wartet"
 *   "Hi Sarah! Neues Angebot" → "Neues Angebot"
 *   "Dear John, your account" → "your account"
 *   "Cher Michel, votre offre" → "votre offre"
 *   "Sehr geehrte Frau Müller, ..." → "..."
 */
const RE_GREETING_PREFIX =
  /^(?:hallo|hi|hey|dear|cher|chère|sehr geehrte[rn]?|bonjour|buenos días|caro|cara)\s+[^,!.;:]+[,!.;:]\s*/i;

/**
 * Erkennt ALL-CAPS-Wörter die typischerweise Personennamen oder
 * tracking-spezifische Tokens sind (z.B. "JOHN", "ABC123XY" nach Grußposition).
 * Nur Wörter >= 4 Zeichen, um Abkürzungen wie "SMS", "VIP" zu schonen.
 *
 * Negative Lookahead: Tokens in eckigen Klammern ([EMAIL], [URL], [NUM])
 * werden NICHT angefasst — verhindert [[NAME]] double-replacement.
 *
 * Hinweis: Wird nach Greeting-Strip angewendet, um verbleibende Name-Tokens
 * zu ersetzen. Bewusst konservativ — keine Volltext-NER.
 */
const RE_ALL_CAPS_LONG = /(?<!\[)\b[A-ZÄÖÜ]{4,}\b(?!\])/g;

// ─── Haupt-Funktion ───────────────────────────────────────────────────────────

/**
 * Sanitiert einen Mail-Betreff für ML-Training:
 * 1. Spracherkennung (franc) auf Raw-Subject — vor Sanitization für bessere Accuracy.
 * 2. E-Mail-Adressen → [EMAIL]
 * 3. URLs → [URL]
 * 4. Zahlen > 4 Stellen → [NUM]
 * 5. Grußwort-Prefix mit Name → strip
 * 6. ALL-CAPS-Wörter >= 4 Zeichen → [NAME] (konservative Heuristik)
 * 7. Whitespace normalisieren
 *
 * Die Reihenfolge ist bedeutsam: URLs vor Emails prüfen (URLs können @-Zeichen
 * enthalten), Greeting vor ALL-CAPS (Greeting-Strip reduziert false positives).
 *
 * Gibt einen leeren String zurück wenn subject null/leer ist.
 */
export function sanitizeSubjectForTraining(
  subject: string | null | undefined,
): SubjectSanitizationResult {
  if (!subject || subject.trim().length === 0) {
    return { subjectSanitized: "", detectedLang: "und" };
  }

  // Schritt 1: Spracherkennung auf dem Raw-Subject (franc braucht natürlichen Text)
  // franc gibt "und" zurück wenn zu kurz oder unbekannt (< ~20 Zeichen oft unsicher).
  const detectedLang = (franc(subject) as string) ?? "und";

  // Schritt 2: Sanitization
  let sanitized = subject;

  // URLs vor E-Mails (URLs können @ enthalten)
  sanitized = sanitized.replace(RE_URL, "[URL]");

  // E-Mail-Adressen
  sanitized = sanitized.replace(RE_EMAIL, "[EMAIL]");

  // Lange Zahlenfolgen (> 4 Stellen)
  sanitized = sanitized.replace(RE_LONG_NUMBER, "[NUM]");

  // Grußwort-Prefix mit Name entfernen
  sanitized = sanitized.replace(RE_GREETING_PREFIX, "");

  // ALL-CAPS-Wörter >= 4 Zeichen → [NAME]
  sanitized = sanitized.replace(RE_ALL_CAPS_LONG, "[NAME]");

  // Whitespace normalisieren (mehrfache Leerzeichen, leading/trailing)
  sanitized = sanitized.replace(/\s+/g, " ").trim();

  return { subjectSanitized: sanitized, detectedLang };
}

/**
 * Wrapper der nur die Spracherkennung ausführt (ohne Sanitization).
 * Nützlich wenn Sanitization bereits anderweitig passiert ist.
 */
export function detectSubjectLanguage(subject: string | null | undefined): string {
  if (!subject || subject.trim().length === 0) return "und";
  return (franc(subject) as string) ?? "und";
}
