import prisma from '../lib/prisma.js';
import { encrypt, decrypt } from '../utils/encryption.js';
import {
  provisionEmail,
  provisionEmailWithMailbox,
  enableMailboxForExistingEmail,
  checkEmailExists,
  getProviderDomain,
  updateMailboxPassword,
  setEmailForwardTargets,
  getActiveProviderConfig,
} from './emailProvider/emailProviderService.js';
import { generateSecurePassword } from '../utils/passwordGenerator.js';
import { ApiError } from '../utils/apiError.js';

// Locker, aber strikt genug gegen offensichtlichen Müll (CRLF, Spaces,
// Komma). Wirklich validiert wird vom Provider beim Sync.
const FORWARD_EMAIL_REGEX = /^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$/;

// Pentest 71.1 (MEDIUM, 2026-06-08): RFC-reservierte und private/
// On-Prem-TLDs. Eine Weiterleitung an `attacker@plesk.internal` würde
// am Provider DNS-Lookups gegen internes Netz auslösen oder bei mDNS-
// Setup an einen lokalen Mailserver gehen. Wir blocken sie hart.
const BLOCKED_TLDS = new Set([
  'local', 'internal', 'corp', 'lan', 'home', 'private',
  'invalid', 'test', 'localhost', 'example',
  'intranet', 'localdomain', 'arpa',
]);

export function parseAdditionalForwards(raw: string | null | undefined): string[] {
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    return parsed.filter((x): x is string => typeof x === 'string' && x.trim() !== '');
  } catch {
    return [];
  }
}

export function serializeAdditionalForwards(list: string[]): string | null {
  const cleaned = list.map((s) => s.trim()).filter((s) => s !== '');
  return cleaned.length === 0 ? null : JSON.stringify(cleaned);
}

/**
 * Liefert eine normalisierte Form der Adresse für den Dedup-Vergleich:
 * lowercase + Plus-Tag aus dem Local-Part rausgestrippt.
 * `billing+pentest@test.de` und `billing@test.de` haben so denselben
 * Schlüssel und treffen sich beim Dedup. Pentest 71.2.
 */
export function canonicalEmailKey(email: string): string {
  const trimmed = email.trim().toLowerCase();
  const at = trimmed.lastIndexOf('@');
  if (at < 1) return trimmed;
  const localPart = trimmed.slice(0, at);
  const domain = trimmed.slice(at + 1);
  const plus = localPart.indexOf('+');
  const cleanedLocal = plus === -1 ? localPart : localPart.slice(0, plus);
  return `${cleanedLocal}@${domain}`;
}

export function assertValidForwardingEmail(value: unknown): string {
  if (typeof value !== 'string') {
    throw new ApiError(400, 'Ungültige Weiterleitungs-E-Mail-Adresse');
  }
  const trimmed = value.trim();
  if (trimmed.length === 0 || trimmed.length > 254) {
    throw new ApiError(400, 'Weiterleitungs-E-Mail-Adresse ist leer oder zu lang');
  }
  if (!FORWARD_EMAIL_REGEX.test(trimmed)) {
    throw new ApiError(400, `Ungültiges E-Mail-Format: ${trimmed}`);
  }
  // 71.1: TLD aus dem Domain-Part rausziehen und gegen die Blocklist
  // halten. Domain liegt nach dem letzten @, TLD nach dem letzten Punkt.
  const domain = trimmed.slice(trimmed.lastIndexOf('@') + 1).toLowerCase();
  const tld = domain.slice(domain.lastIndexOf('.') + 1);
  if (BLOCKED_TLDS.has(tld)) {
    throw new ApiError(400, `Top-Level-Domain "${tld}" ist nicht erlaubt (reservierte/private TLD).`);
  }
  return trimmed.toLowerCase();
}

export async function getEmailsByCustomerId(customerId: number, includeInactive = false) {
  const where: Record<string, unknown> = { customerId };
  if (!includeInactive) {
    where.isActive = true;
  }
  return prisma.stressfreiEmail.findMany({
    where,
    orderBy: { createdAt: 'desc' },
  });
}

// Mit Mailbox-Status für E-Mail-Client
export async function getEmailsWithMailboxByCustomerId(customerId: number) {
  return prisma.stressfreiEmail.findMany({
    where: {
      customerId,
      isActive: true,
      hasMailbox: true,
    },
    select: {
      id: true,
      email: true,
      notes: true,
      hasMailbox: true,
      _count: {
        select: {
          cachedEmails: true,
        },
      },
    },
    orderBy: { email: 'asc' },
  });
}

export async function getEmailById(id: number) {
  return prisma.stressfreiEmail.findUnique({
    where: { id },
  });
}

// E-Mail mit Mailbox-Status laden
export async function getEmailWithMailboxById(id: number) {
  return prisma.stressfreiEmail.findUnique({
    where: { id },
    select: {
      id: true,
      customerId: true,
      email: true,
      platform: true,
      notes: true,
      isActive: true,
      hasMailbox: true,
      emailPasswordEncrypted: true,
      createdAt: true,
      updatedAt: true,
    },
  });
}

export interface CreateEmailData {
  customerId: number;
  email: string;
  platform?: string;
  notes?: string;
  provisionAtProvider?: boolean;
  createMailbox?: boolean;
}

export async function createEmail(data: CreateEmailData) {
  const { provisionAtProvider, createMailbox, ...emailData } = data;

  // Duplikatscheck: pro Kunde darf eine Stressfrei-Adresse nur einmal
  // existieren. Case-insensitive, weil RFC-localpart-Großschreibung in
  // der Praxis nie semantischen Unterschied macht und der Provider eh
  // einheitlich lowercased.
  const normalized = data.email.trim().toLowerCase();
  const conflict = await prisma.stressfreiEmail.findFirst({
    where: {
      customerId: data.customerId,
      email: { equals: normalized },
    },
    select: { id: true, isActive: true },
  });
  if (conflict) {
    const hint = conflict.isActive
      ? 'Diese E-Mail-Adresse ist bei diesem Kunden bereits angelegt.'
      : 'Diese E-Mail-Adresse existiert bei diesem Kunden bereits (deaktiviert). Bitte reaktiviere den vorhandenen Eintrag, statt einen neuen anzulegen.';
    throw new ApiError(409, hint);
  }
  // Wert in DB ist eh schon lowercase – wir setzen es einheitlich.
  emailData.email = normalized;

  // Falls beim Provider anlegen gewünscht
  if (provisionAtProvider) {
    // Kunde laden für Weiterleitung
    const customer = await prisma.customer.findUnique({
      where: { id: data.customerId },
      select: { email: true },
    });

    if (!customer?.email) {
      throw new Error('Kunde hat keine E-Mail-Adresse für Weiterleitung');
    }

    // LocalPart extrahieren
    const localPart = data.email.split('@')[0];

    if (createMailbox) {
      // Mit echter Mailbox anlegen. Immer ein frisches, sicheres Passwort
      // erzeugen.
      const password = generateSecurePassword();
      const result = await provisionEmailWithMailbox(localPart, customer.email, password);

      if (!result.success) {
        throw new Error(result.error || 'Fehler beim Anlegen der Mailbox');
      }

      // Mailbox verbindlich aktivieren UND Passwort setzen. Beim Neu-Anlegen
      // hat createEmailWithMailbox das schon getan (der folgende Call ist dann
      // idempotent), ABER wenn die Adresse beim Provider bereits als reine
      // Weiterleitung existierte, kehrt provisionEmailWithMailbox früh mit
      // success zurück, ohne je die Mailbox zu aktivieren. Ohne diesen Schritt
      // läge im CRM ein verschlüsseltes Passwort, das der Provider gar nicht
      // kennt → IMAP/SMTP-Login schlägt fehl.
      //
      // WICHTIG (Pentest R130): hier MUSS enableMailboxForExistingEmail
      // verwendet werden, nicht updateMailboxPassword. Letzteres setzt bei
      // Plesk nur `-passwd`, lässt die Adresse aber auf `-mailbox false`
      // stehen – die Mailbox wird also nie aktiviert und der Login scheitert
      // trotz korrektem Passwort. enableMailboxForExisting setzt
      // `-mailbox true -passwd ...` und deckt beide Fälle idempotent ab.
      const pwResult = await enableMailboxForExistingEmail(localPart, password);
      if (!pwResult.success) {
        throw new Error(
          pwResult.error || 'Mailbox angelegt, aber Postfach-Passwort konnte nicht gesetzt werden',
        );
      }

      // Passwort verschlüsseln und speichern
      const passwordEncrypted = encrypt(password);

      return prisma.stressfreiEmail.create({
        data: {
          ...emailData,
          isActive: true,
          hasMailbox: true,
          isProvisioned: true,
          provisionedAt: new Date(),
          emailPasswordEncrypted: passwordEncrypted,
        },
      });
    } else {
      // Nur Weiterleitung anlegen
      const result = await provisionEmail(localPart, customer.email);

      if (!result.success && !result.message?.includes('existiert bereits')) {
        throw new Error(result.error || 'Fehler beim Anlegen der E-Mail');
      }
    }
  }

  return prisma.stressfreiEmail.create({
    data: {
      ...emailData,
      isActive: true,
      hasMailbox: createMailbox || false,
      // Provisioned-Flag nur setzen wenn Provider-Aufruf gerade lief (oder
      // die Mail bei Plesk schon existierte und der „existiert bereits"-Pfad
      // gegriffen hat).
      isProvisioned: !!provisionAtProvider,
      provisionedAt: provisionAtProvider ? new Date() : null,
    },
  });
}

export async function updateEmail(
  id: number,
  data: {
    email?: string;
    platform?: string;
    notes?: string;
    isActive?: boolean;
  }
) {
  // Beim Umbenennen der E-Mail-Adresse erneut Kollisionscheck. Sonst
  // kann man eine zweite Adresse mit identischer Mail beim selben Kunden
  // anlegen (Umweg um den Create-Check).
  if (typeof data.email === 'string' && data.email.trim() !== '') {
    const normalized = data.email.trim().toLowerCase();
    const current = await prisma.stressfreiEmail.findUnique({
      where: { id },
      select: { customerId: true, email: true },
    });
    if (!current) {
      throw new ApiError(404, 'StressfreiEmail nicht gefunden');
    }
    if (normalized !== current.email.toLowerCase()) {
      const conflict = await prisma.stressfreiEmail.findFirst({
        where: {
          customerId: current.customerId,
          email: { equals: normalized },
          NOT: { id },
        },
        select: { id: true },
      });
      if (conflict) {
        throw new ApiError(409, 'Diese E-Mail-Adresse ist bei diesem Kunden bereits angelegt.');
      }
    }
    data.email = normalized;
  }

  return prisma.stressfreiEmail.update({
    where: { id },
    data,
  });
}

export async function deleteEmail(id: number) {
  return prisma.stressfreiEmail.delete({ where: { id } });
}

/**
 * Komplette Liste zusätzlicher Weiterleitungs-E-Mails ersetzen und
 * direkt mit dem Provider synchronisieren. Aufrufer hat eine canonical
 * Liste – das Sub-Modal arbeitet auf Snapshot-Basis.
 *
 * Pentest 71.2: Dedup über `canonicalEmailKey` (Plus-Tags strippen),
 * damit `billing+tag@x.de` und `billing@x.de` als gleiches Ziel
 * erkannt werden – auch im Vergleich zur Stamm-E-Mail des Kunden.
 *
 * Pentest 71.4: DB-Update wird bei Provider-Sync-Fehler zurückgerollt,
 * damit Plesk und DB nicht auseinanderlaufen.
 *
 * Pentest 81.1: Self-Forward wird hart abgelehnt – würde sonst am
 * Provider einen Mail-Loop erzeugen (Stressfrei-Adresse leitet auf
 * sich selbst um → unendliche Weiterleitung).
 */
export async function setAdditionalForwards(
  id: number,
  emails: string[],
): Promise<{ success: boolean; forwardTargets?: string[]; error?: string }> {
  // Kunden-Stamm-Mail + eigene Email holen für Dedup gegen die fest
  // gesetzten Ziele bzw. die Stressfrei-Adresse selbst.
  const meta = await prisma.stressfreiEmail.findUnique({
    where: { id },
    select: {
      email: true,
      additionalForwardingEmails: true,
      customer: { select: { email: true } },
    },
  });
  if (!meta) {
    throw new ApiError(404, 'StressfreiEmail nicht gefunden');
  }
  const previousRaw = meta.additionalForwardingEmails;
  const customerEmailKey = meta.customer?.email
    ? canonicalEmailKey(meta.customer.email)
    : null;
  const selfKey = canonicalEmailKey(meta.email);

  // Input normalisieren + Duplikate raus.
  const seen = new Set<string>();
  if (customerEmailKey) seen.add(customerEmailKey);
  const cleaned: string[] = [];
  for (const raw of emails) {
    const ok = assertValidForwardingEmail(raw);
    const key = canonicalEmailKey(ok);
    // 81.1: Eintrag, der auf die Adresse selbst zeigt, würde einen
    // Mail-Loop am Provider erzeugen. Hart ablehnen mit klarer
    // Fehlermeldung, statt silent zu droppen – der User soll merken,
    // dass sein Eintrag bewusst nicht akzeptiert wurde.
    if (key === selfKey) {
      throw new ApiError(
        400,
        `"${ok}" zeigt auf die Adresse selbst – Mail-Loop. Bitte eine andere Weiterleitungsadresse wählen.`,
      );
    }
    if (!seen.has(key)) {
      seen.add(key);
      cleaned.push(ok);
    }
  }

  const nextRaw = serializeAdditionalForwards(cleaned);
  await prisma.stressfreiEmail.update({
    where: { id },
    data: { additionalForwardingEmails: nextRaw },
  });

  // Provider unmittelbar nachziehen, sonst läuft das Plesk-Mail-Konto
  // mit der alten Liste weiter. autoImport=false, weil unsere DB-Liste
  // hier die explizite User-Intent ist – kein Plesk-Member-Auto-Pull,
  // sonst landen gerade entfernte Adressen zurück in der Liste.
  const syncResult = await syncForwardingForEmail(id, { autoImportPleskMembers: false });

  // 71.4: Rollback wenn Plesk den Sync abgelehnt hat. DB darf nicht
  // den optimistischen Stand zeigen, wenn der Provider noch auf dem
  // alten Stand ist.
  if (!syncResult.success && previousRaw !== nextRaw) {
    await prisma.stressfreiEmail.update({
      where: { id },
      data: { additionalForwardingEmails: previousRaw },
    }).catch((rollbackErr) => {
      console.error(
        '[setAdditionalForwards] Rollback nach Provider-Fail fehlgeschlagen:',
        rollbackErr,
      );
    });
  }

  return syncResult;
}

// Mailbox nachträglich aktivieren (für existierende E-Mail-Weiterleitung)
export async function enableMailbox(id: number): Promise<{ success: boolean; error?: string }> {
  const stressfreiEmail = await prisma.stressfreiEmail.findUnique({
    where: { id },
  });

  if (!stressfreiEmail) {
    return { success: false, error: 'StressfreiEmail nicht gefunden' };
  }

  if (stressfreiEmail.hasMailbox) {
    return { success: false, error: 'Mailbox ist bereits aktiviert' };
  }

  const localPart = stressfreiEmail.email.split('@')[0];
  const password = generateSecurePassword();

  // Mailbox für existierende E-Mail aktivieren (nicht neu erstellen!)
  const result = await enableMailboxForExistingEmail(localPart, password);

  if (!result.success) {
    return { success: false, error: result.error || 'Fehler beim Aktivieren der Mailbox' };
  }

  // Passwort verschlüsseln und speichern
  const passwordEncrypted = encrypt(password);

  await prisma.stressfreiEmail.update({
    where: { id },
    data: {
      hasMailbox: true,
      emailPasswordEncrypted: passwordEncrypted,
    },
  });

  return { success: true };
}

// Mailbox-Status mit Provider synchronisieren
export async function syncMailboxStatus(id: number): Promise<{
  success: boolean;
  hasMailbox?: boolean;
  wasUpdated?: boolean;
  error?: string
}> {
  const stressfreiEmail = await prisma.stressfreiEmail.findUnique({
    where: { id },
    select: { email: true, hasMailbox: true, isProvisioned: true, provisionedAt: true },
  });

  if (!stressfreiEmail) {
    return { success: false, error: 'StressfreiEmail nicht gefunden' };
  }

  const localPart = stressfreiEmail.email.split('@')[0];

  // Provider-Status prüfen
  const providerStatus = await checkEmailExists(localPart);

  // Self-Healing für `isProvisioned`: das Flag wurde in einer früheren Code-
  // Version beim Provisioning nie gesetzt → DB ist stellenweise inkonsistent
  // zum Provider. Wir reconciliieren bei jedem Status-Sync mit.
  const updates: Record<string, unknown> = {};

  if (!providerStatus.exists) {
    // Beim Provider nicht (mehr) vorhanden → DB-Flag entsprechend
    if (stressfreiEmail.isProvisioned) {
      updates.isProvisioned = false;
    }
    if (stressfreiEmail.hasMailbox) {
      updates.hasMailbox = false;
    }
    if (Object.keys(updates).length > 0) {
      await prisma.stressfreiEmail.update({ where: { id }, data: updates });
      return { success: true, hasMailbox: false, wasUpdated: true };
    }
    return { success: true, hasMailbox: false, wasUpdated: false };
  }

  // Beim Provider vorhanden → isProvisioned auf true ziehen falls noch nicht
  if (!stressfreiEmail.isProvisioned) {
    updates.isProvisioned = true;
    if (!stressfreiEmail.provisionedAt) {
      updates.provisionedAt = new Date();
    }
  }

  const providerHasMailbox = providerStatus.hasMailbox === true;
  if (stressfreiEmail.hasMailbox !== providerHasMailbox) {
    updates.hasMailbox = providerHasMailbox;
  }

  if (Object.keys(updates).length > 0) {
    await prisma.stressfreiEmail.update({ where: { id }, data: updates });
    console.log(`Stressfrei-Status für ${stressfreiEmail.email} reconciled:`, updates);
    return { success: true, hasMailbox: providerHasMailbox, wasUpdated: true };
  }

  return { success: true, hasMailbox: providerHasMailbox, wasUpdated: false };
}

// Passwort für IMAP/SMTP-Zugang entschlüsseln (nur für autorisierte Nutzung)
export async function getDecryptedPassword(id: number): Promise<string | null> {
  const stressfreiEmail = await prisma.stressfreiEmail.findUnique({
    where: { id },
    select: { emailPasswordEncrypted: true },
  });

  if (!stressfreiEmail?.emailPasswordEncrypted) {
    return null;
  }

  try {
    return decrypt(stressfreiEmail.emailPasswordEncrypted);
  } catch {
    console.error('Fehler beim Entschlüsseln des Passworts');
    return null;
  }
}

// Weiterleitungen einer Stressfrei-Adresse neu setzen (z.B. nach Änderung der
// Stamm-E-Mail des Kunden). Ersetzt alle bestehenden Forwards durch
// [aktuelle Kunden-E-Mail, defaultForwardEmail aus Provider-Config].
//
// Wenn die Adresse `hasMailbox` ist: setzt zusätzlich das im CRM verschlüsselt
// hinterlegte Passwort am Provider neu (Use-Case: Plesk-Restore, manueller
// Eingriff im Plesk-UI etc. – CRM und Provider können sich entkoppeln, sodass
// IMAP/SMTP-Logins im CRM nicht mehr passen). Self-Healing.
//
// Idempotent: das Plesk-CLI `set:` überschreibt die Adressliste komplett, kein
// Duplikat-Risiko bei Mehrfachaufruf. Wenn die Operation erfolgreich war wird
// das `isProvisioned`-Flag automatisch auf `true` gezogen (historische
// Einträge, bei denen das Flag nie gesetzt wurde, werden so geheilt).
export async function syncForwardingForEmail(
  id: number,
  options: { autoImportPleskMembers?: boolean } = {},
): Promise<{
  success: boolean;
  forwardTargets?: string[];
  customerEmail?: string;
  passwordReset?: boolean;
  error?: string;
}> {
  // Auto-Import übernimmt unbekannte Plesk-Members in unsere DB. Macht
  // beim Sync-Button Sinn (Bestands-Migration), aber NICHT beim
  // User-getriggerten Add/Remove – dort ist die DB-Liste die Wahrheit.
  // Sonst kreisen entfernte Adressen zurück in die Liste:
  //   1. User entfernt c → DB=[a,b], Plesk=[a,b,c]
  //   2. Auto-Import: "c ist in Plesk aber nicht in DB → in DB schreiben"
  //   3. → DB=[a,b,c], Diff sagt nichts zu löschen, Plesk bleibt [a,b,c].
  const autoImport = options.autoImportPleskMembers ?? true;
  const stressfreiEmail = await prisma.stressfreiEmail.findUnique({
    where: { id },
    select: {
      email: true,
      customerId: true,
      isProvisioned: true,
      hasMailbox: true,
      emailPasswordEncrypted: true,
      additionalForwardingEmails: true,
    },
  });

  if (!stressfreiEmail) {
    return { success: false, error: 'StressfreiEmail nicht gefunden' };
  }

  const customer = await prisma.customer.findUnique({
    where: { id: stressfreiEmail.customerId },
    select: { email: true },
  });
  if (!customer?.email) {
    return { success: false, error: 'Kunde hat keine Stamm-E-Mail-Adresse hinterlegt' };
  }

  const config = await getActiveProviderConfig();
  const forwardTargets: string[] = [customer.email];
  if (config?.defaultForwardEmail) {
    forwardTargets.push(config.defaultForwardEmail);
  }
  // Zusätzliche Weiterleitungsziele (vom User im Modal gepflegt). Duplikate
  // gegen die Stamm-Mail oder den Default werden hier weggefiltert, damit
  // Plesk nicht mit Wiederholungen die Liste aufbläht. Pentest 71.2:
  // Vergleich über `canonicalEmailKey`, damit Plus-Tags nicht doppelt
  // zustellen.
  const seenKeys = new Set(forwardTargets.map(canonicalEmailKey));
  for (const extra of parseAdditionalForwards(stressfreiEmail.additionalForwardingEmails)) {
    const key = canonicalEmailKey(extra);
    if (!seenKeys.has(key)) {
      seenKeys.add(key);
      forwardTargets.push(extra);
    }
  }

  const localPart = stressfreiEmail.email.split('@')[0];

  // 0) Auto-Migration: Plesk hat zwei Verteil-Mechanismen (Mailgroup +
  // Forwarding). Alt-Anlagen liefen oft via Mailgroup – unser Sync
  // schreibt aber nur in die Forwarding-Liste, daher landeten neue
  // Adressen nirgendwo. Hier holen wir die aktuellen Mailgroup-Members
  // ab und ziehen alle, die wir nicht schon kennen, in unsere
  // additionalForwardingEmails-Liste rein. Der nachfolgende Plesk-Call
  // deaktiviert dann die Mailgroup und schreibt die volle Liste als
  // Forwarding. Verlustfrei – kein Empfänger fällt raus.
  // Pentest 83.2: Self-Forward auch beim Import blocken. Die
  // Stressfrei-Adresse selbst darf nicht aus Plesk in unsere DB
  // landen – sonst läuft sie nach dem Mailgroup→Forwarding-Umschalten
  // als Forwarding-Target auf sich selbst (Mail-Loop).
  seenKeys.add(canonicalEmailKey(stressfreiEmail.email));

  if (autoImport) {
    try {
      const pleskState = await checkEmailExists(localPart);
      const existingMembers = [
        ...(pleskState.mailgroupMembers ?? []),
        ...(pleskState.forwardingTargets ?? []),
      ];
      const newImports: string[] = [];
      for (const member of existingMembers) {
        // Pentest 83.1: importierte Adressen aus Plesk müssen denselben
        // Filter passieren wie User-Eingaben (TLD-Blocklist, Format).
        // Sonst rutschen reservierte TLDs wie `.internal` ohne Check
        // in unsere DB, falls ein Plesk-Admin sie dort manuell gepflegt
        // hat. Ungültige werden silent gedroppt – Log informiert.
        let validated: string;
        try {
          validated = assertValidForwardingEmail(member);
        } catch (validationErr) {
          const reason = validationErr instanceof Error ? validationErr.message : 'unbekannt';
          console.debug(
            `[syncForwardingForEmail] Plesk-Member "${member}" verworfen: ${reason}`,
          );
          continue;
        }
        const key = canonicalEmailKey(validated);
        if (!seenKeys.has(key)) {
          seenKeys.add(key);
          forwardTargets.push(validated);
          newImports.push(validated);
        }
      }
      if (newImports.length > 0) {
        const mergedAdditional = [
          ...parseAdditionalForwards(stressfreiEmail.additionalForwardingEmails),
          ...newImports,
        ];
        await prisma.stressfreiEmail.update({
          where: { id },
          data: { additionalForwardingEmails: serializeAdditionalForwards(mergedAdditional) },
        });
        // Pentest 83.3: PII-Logs auf debug-Level statt log-Level.
        console.debug(
          `[syncForwardingForEmail] Importiert aus Plesk-Mailgroup für ${stressfreiEmail.email}:`,
          newImports,
        );
      }
    } catch (importErr) {
      // Nicht hart fehlschlagen – im schlimmsten Fall fehlen ein paar
      // alte Empfänger, aber der eigentliche Sync soll trotzdem laufen.
      console.error('[syncForwardingForEmail] Mailgroup-Import fehlgeschlagen:', importErr);
    }
  }

  // 1) Forwards neu setzen (deaktiviert intern Mailgroup).
  const forwardResult = await setEmailForwardTargets(localPart, forwardTargets);
  if (!forwardResult.success) {
    // Wenn Plesk meldet „nicht gefunden", liefern wir eine sprechende Meldung
    // statt der rohen Provider-Nachricht.
    const err = forwardResult.error || 'Provider-Update fehlgeschlagen';
    const friendly = /not\s*found|nicht\s*gefunden/i.test(err)
      ? 'E-Mail-Adresse beim Provider nicht gefunden – wurde sie dort gelöscht?'
      : err;
    return { success: false, error: friendly };
  }

  // 2) Wenn Mailbox: Passwort aus CRM-Speicher entschlüsseln und am Provider
  //    neu setzen (Self-Healing nach Provider-seitigen Änderungen).
  let passwordReset = false;
  if (stressfreiEmail.hasMailbox && stressfreiEmail.emailPasswordEncrypted) {
    try {
      const password = decrypt(stressfreiEmail.emailPasswordEncrypted);
      const pwResult = await updateMailboxPassword(localPart, password);
      if (!pwResult.success) {
        // Forwards waren schon erfolgreich – wir geben Forward-Erfolg + Passwort-
        // Fehler kombiniert zurück, statt die ganze Operation rot zu machen.
        return {
          success: false,
          forwardTargets,
          customerEmail: customer.email,
          error:
            'Weiterleitungen aktualisiert, aber Passwort-Sync fehlgeschlagen: ' +
            (pwResult.error || 'unbekannt'),
        };
      }
      passwordReset = true;
    } catch (e) {
      return {
        success: false,
        forwardTargets,
        customerEmail: customer.email,
        error:
          'Weiterleitungen aktualisiert, aber Passwort konnte nicht entschlüsselt werden – ' +
          'evtl. wurde der ENCRYPTION_KEY rotiert',
      };
    }
  }

  // 3) Self-Healing: nach erfolgreichem Provider-Aufruf wissen wir definitiv,
  //    dass die Adresse beim Provider existiert → Flag korrigieren.
  if (!stressfreiEmail.isProvisioned) {
    await prisma.stressfreiEmail.update({
      where: { id },
      data: { isProvisioned: true, provisionedAt: new Date() },
    });
  }

  return {
    success: true,
    forwardTargets,
    customerEmail: customer.email,
    passwordReset,
  };
}

// Passwort neu generieren und beim Provider setzen
export async function resetMailboxPassword(id: number): Promise<{ success: boolean; password?: string; error?: string }> {
  const stressfreiEmail = await prisma.stressfreiEmail.findUnique({
    where: { id },
    select: { email: true, hasMailbox: true },
  });

  if (!stressfreiEmail) {
    return { success: false, error: 'StressfreiEmail nicht gefunden' };
  }

  if (!stressfreiEmail.hasMailbox) {
    return { success: false, error: 'Keine Mailbox für diese E-Mail-Adresse' };
  }

  // Neues Passwort generieren
  const newPassword = generateSecurePassword();
  const localPart = stressfreiEmail.email.split('@')[0];

  // Passwort beim Provider ändern
  const providerResult = await updateMailboxPassword(localPart, newPassword);
  if (!providerResult.success) {
    return { success: false, error: providerResult.error || 'Fehler beim Aktualisieren des Passworts beim Provider' };
  }

  // Passwort verschlüsseln und lokal speichern
  const passwordEncrypted = encrypt(newPassword);

  await prisma.stressfreiEmail.update({
    where: { id },
    data: { emailPasswordEncrypted: passwordEncrypted },
  });

  return { success: true, password: newPassword };
}
