// ==================== IMAP SERVICE ====================
// Service für IMAP-Zugriff auf Mailboxen

import { ImapFlow, FetchMessageObject } from 'imapflow';
import { simpleParser, ParsedMail, AddressObject } from 'mailparser';

// Verschlüsselungstyp
export type MailEncryption = 'SSL' | 'STARTTLS' | 'NONE';

/**
 * Zieht eine menschenlesbare Fehlermeldung aus einem imapflow-Error.
 * `imapflow` wirft bei jedem IMAP-NO/BAD-Response immer nur
 * `new Error('Command failed')` und legt den echten Grund in
 * `err.responseText` / `err.responseStatus` ab. Ohne diese Extraktion
 * sähe der User im UI nur "Command failed" ohne Kontext (das war der
 * ursprüngliche Bug 2026-07-11: Passwort war falsch, gemeldet wurde
 * nur "Command failed").
 *
 * Zusätzlich mappen wir häufige Fehler-Klassen auf klare Meldungen
 * mit Handlungsanweisung – gilt sowohl für Anhang-Download als auch
 * für Postfach-Sync, damit der User weiß was zu tun ist.
 */
export function humanizeImapError(error: unknown): string {
  const anyErr = error as {
    message?: string;
    responseText?: string;
    responseStatus?: string;
    authenticationFailed?: boolean;
    code?: string;
  };
  const rawText = anyErr?.responseText || anyErr?.message || 'Unbekannter Fehler';
  const statusTag = anyErr?.responseStatus ? `${anyErr.responseStatus} ` : '';
  const combined = `${statusTag}${rawText}`;
  const lower = combined.toLowerCase();

  // 1) Auth-Fehler explizit erkennen – häufigste Ursache in der Praxis.
  //    Passwort im CRM stimmt nicht mehr mit dem am Provider überein
  //    (Passwort geändert / abgelaufen / Postfach neu angelegt).
  if (
    anyErr?.authenticationFailed
    || lower.includes('authentication failed')
    || lower.includes('auth failed')
    || lower.includes('invalid credentials')
    || lower.includes('login failed')
    || lower.includes('logindisabled')
    || (anyErr?.responseStatus === 'NO' && lower.includes('auth'))
  ) {
    return 'IMAP-Login abgelehnt. Das gespeicherte Postfach-Passwort stimmt nicht mehr. Bitte im Postfach "Zugangsdaten synchronisieren" ausführen oder das Passwort neu setzen.';
  }

  // 2) UID-Stale-Fehler beim Fetch: E-Mail existiert IMAP-seitig nicht mehr.
  if (lower.includes('no longer exist') || lower.includes('no such message')) {
    return 'Nachricht existiert im IMAP-Postfach nicht mehr (wahrscheinlich verschoben oder gelöscht). Bitte E-Mail-Liste neu synchronisieren.';
  }

  // 3) Netzwerk-/TLS-Fehler
  if (lower.includes('socket disconnected') && lower.includes('tls')) {
    return 'IMAP-Server hat die TLS-Verbindung abgelehnt. Mögliche Ursache: selbstsigniertes Zertifikat. Bitte in den E-Mail-Provider-Einstellungen "Selbstsignierte Zertifikate erlauben" aktivieren.';
  }
  if (lower.includes('econnrefused')) {
    return 'IMAP-Server ist nicht erreichbar (Verbindung verweigert). Bitte Server/Port prüfen.';
  }
  if (lower.includes('etimedout')) {
    return 'Zeitüberschreitung beim Verbinden zum IMAP-Server. Bitte später erneut versuchen.';
  }

  // 4) Fallback: den vom Server gelieferten Text nehmen – der ist meist
  //    schon aussagekräftig ("BAD Session expired." etc.). Wenn wir hier
  //    gar nichts hätten, käme jetzt zumindest der Status-Tag durch.
  return combined;
}

export interface ImapCredentials {
  host: string;
  port: number;
  user: string;
  password: string;
  encryption?: MailEncryption;     // SSL, STARTTLS oder NONE (Standard: SSL)
  allowSelfSignedCerts?: boolean;  // Selbstsignierte Zertifikate erlauben
  // DNS-Rebinding-Schutz: Caller hat den Hostname zu IP aufgelöst und
  // setzt host=IP, servername=originalHostname für TLS-SNI / Cert-Validation.
  servername?: string;
}

/**
 * TLS-Optionen für IMAP-Verbindungen zusammenbauen.
 * Wenn `allowSelfSignedCerts` aktiv ist, werden zusätzlich ältere TLS-Versionen
 * (TLS 1.0+) und legacy Cipher-Suites erlaubt – hilfreich bei älteren Mailservern,
 * die sonst den Socket sofort nach Connect schließen.
 */
function buildTlsOptions(credentials: ImapCredentials): Record<string, unknown> | undefined {
  const encryption = credentials.encryption ?? 'SSL';
  if (encryption === 'NONE') return undefined;

  const rejectUnauthorized = !credentials.allowSelfSignedCerts;
  const options: Record<string, unknown> = { rejectUnauthorized };

  // DNS-Rebinding-Schutz: wenn host eine IP ist und der ursprüngliche
  // Hostname als servername mitgeliefert wird, nutze ihn für SNI/Cert.
  if (credentials.servername) {
    options.servername = credentials.servername;
  }

  if (credentials.allowSelfSignedCerts) {
    options.minVersion = 'TLSv1';
    options.ciphers = 'DEFAULT:@SECLEVEL=0';
  }

  return options;
}

export interface FetchedEmail {
  uid: number;
  messageId: string;
  subject: string | null;
  fromAddress: string;
  fromName: string | null;
  toAddresses: string[];
  ccAddresses: string[];
  date: Date;
  textBody: string | null;
  htmlBody: string | null;
  hasAttachments: boolean;
  attachmentNames: string[];
}

export interface FetchOptions {
  folder?: string;      // Default: 'INBOX'
  since?: Date;         // Nur E-Mails nach diesem Datum
  limit?: number;       // Max. Anzahl E-Mails
  sinceUid?: number;    // Nur E-Mails ab dieser UID (für inkrementellen Sync)
}

// Helper: Adressen aus mailparser-Format extrahieren
function extractAddresses(addressObj: AddressObject | AddressObject[] | undefined): string[] {
  if (!addressObj) return [];

  const addresses = Array.isArray(addressObj) ? addressObj : [addressObj];
  const result: string[] = [];

  for (const obj of addresses) {
    if (obj.value) {
      for (const addr of obj.value) {
        if (addr.address) {
          result.push(addr.address);
        }
      }
    }
  }

  return result;
}

// Helper: Ersten Absender-Namen extrahieren
function extractFromName(addressObj: AddressObject | AddressObject[] | undefined): string | null {
  if (!addressObj) return null;

  const addresses = Array.isArray(addressObj) ? addressObj : [addressObj];

  for (const obj of addresses) {
    if (obj.value && obj.value[0]) {
      return obj.value[0].name || null;
    }
  }

  return null;
}

// E-Mails aus einer Mailbox abrufen
export async function fetchEmails(
  credentials: ImapCredentials,
  options: FetchOptions = {}
): Promise<FetchedEmail[]> {
  const {
    folder = 'INBOX',
    since,
    limit = 50,
    sinceUid,
  } = options;

  // Verschlüsselungs-Einstellungen basierend auf Modus
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  // ImapFlow-Optionen je nach Verschlüsselungstyp
  // SSL: secure=true (implicit TLS, Port 993)
  // STARTTLS: secure=false (upgrades to TLS, Port 143)
  // NONE: secure=false + disableAutoIdle (no encryption, Port 143)
  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  // TLS-Optionen nur wenn nicht NONE
  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  // Debug-Logging
  console.log(`[IMAP] Connecting to ${credentials.host}:${credentials.port} (${encryption}), user: ${credentials.user}`);

  const client = new ImapFlow(clientOptions);

  const emails: FetchedEmail[] = [];

  try {
    await client.connect();
    console.log(`[IMAP] Connected successfully`);

    // Mailbox öffnen
    await client.mailboxOpen(folder);

    // Suchkriterien zusammenstellen
    let searchCriteria: { since?: Date; uid?: string } = {};

    if (since) {
      searchCriteria.since = since;
    }

    // IMAP SEARCH ausführen
    let uids: number[];

    if (sinceUid) {
      // Inkrementeller Sync: Nur E-Mails ab einer bestimmten UID
      // IMAP UID-Range: "sinceUid:*" bedeutet alle E-Mails >= sinceUid
      const messages = await client.search({ uid: `${sinceUid}:*` }, { uid: true });
      const messageArray = Array.isArray(messages) ? messages : [];
      uids = messageArray.filter((uid: number) => uid > sinceUid); // Exkludiere die sinceUid selbst
    } else if (since) {
      // Nach Datum suchen
      const messages = await client.search({ since }, { uid: true });
      uids = Array.isArray(messages) ? messages : [];
    } else {
      // Alle E-Mails (mit Limit)
      const messages = await client.search({ all: true }, { uid: true });
      uids = Array.isArray(messages) ? messages : [];
    }

    // Neueste zuerst (absteigend sortieren)
    uids.sort((a, b) => b - a);

    // Limit anwenden
    const limitedUids = uids.slice(0, limit);

    console.log(`[IMAP] Found ${uids.length} emails, fetching ${limitedUids.length}`);

    if (limitedUids.length === 0) {
      console.log(`[IMAP] No emails to fetch`);
      await client.logout();
      return [];
    }

    // E-Mails abrufen - drittes Argument { uid: true } für UID FETCH
    for await (const message of client.fetch(limitedUids.join(','), {
      uid: true, // UID im Response inkludieren
      envelope: true,
      source: true, // Vollständige E-Mail für Parsing
    }, { uid: true })) {
      try {
        // Source muss vorhanden sein
        if (!message.source) {
          console.error(`E-Mail UID ${message.uid} hat keine Source`);
          continue;
        }

        // E-Mail mit mailparser parsen
        const parsed = await simpleParser(message.source) as ParsedMail;

        const email: FetchedEmail = {
          uid: message.uid,
          messageId: parsed.messageId || `${message.uid}@unknown`,
          subject: parsed.subject || null,
          fromAddress: extractAddresses(parsed.from)[0] || 'unknown@unknown',
          fromName: extractFromName(parsed.from),
          toAddresses: extractAddresses(parsed.to),
          ccAddresses: extractAddresses(parsed.cc),
          date: parsed.date || new Date(),
          textBody: parsed.text || null,
          htmlBody: parsed.html ? String(parsed.html) : null,
          hasAttachments: (parsed.attachments?.length || 0) > 0,
          attachmentNames: parsed.attachments?.map((a) => a.filename || 'unnamed') || [],
        };

        emails.push(email);
      } catch (parseError) {
        console.error(`Fehler beim Parsen von E-Mail UID ${message.uid}:`, parseError);
        // E-Mail überspringen bei Parse-Fehlern
      }
    }

    await client.logout();
  } catch (error) {
    // Verbindung sauber schließen bei Fehlern
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    // Bessere Fehlermeldungen
    if (error instanceof Error) {
      const msg = error.message.toLowerCase();
      const errorCode = (error as NodeJS.ErrnoException).code?.toLowerCase() || '';

      if (msg.includes('authentication') || msg.includes('login')) {
        throw new Error('IMAP-Authentifizierung fehlgeschlagen - Zugangsdaten prüfen');
      }
      if (msg.includes('econnrefused') || errorCode === 'econnrefused') {
        throw new Error(`IMAP-Server nicht erreichbar: ${credentials.host}:${credentials.port} - Verbindung verweigert`);
      }
      if (msg.includes('timeout') || msg.includes('etimedout') || errorCode === 'etimedout') {
        const enc = credentials.encryption ?? 'SSL';
        if (enc === 'STARTTLS' && credentials.port === 143) {
          throw new Error(`IMAP Port 143 (STARTTLS) nicht erreichbar auf ${credentials.host}`);
        } else if (enc === 'SSL' && credentials.port === 993) {
          throw new Error(`IMAP Port 993 (SSL) nicht erreichbar auf ${credentials.host}`);
        } else {
          throw new Error(`IMAP-Verbindung zu ${credentials.host}:${credentials.port} fehlgeschlagen - Timeout`);
        }
      }
      if (msg.includes('certificate') || msg.includes('cert')) {
        throw new Error('IMAP SSL-Zertifikatfehler - Aktiviere "Selbstsignierte Zertifikate erlauben"');
      }
    }

    throw error;
  }

  return emails;
}

// Verbindung testen
export async function testImapConnection(credentials: ImapCredentials): Promise<void> {
  // Verschlüsselungs-Einstellungen basierend auf Modus
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();
    await client.logout();
  } catch (error) {
    // Verbindung sauber schließen bei Fehlern
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    // Rohes Error-Objekt loggen, damit wir ImapFlow-spezifische Felder sehen
    console.error('[testImapConnection] Raw error:', error);
    if (error && typeof error === 'object') {
      const e = error as any;
      console.error('[testImapConnection] Details:', {
        code: e.code,
        response: e.response,
        responseStatus: e.responseStatus,
        responseText: e.responseText,
        authenticationFailed: e.authenticationFailed,
        serverResponseCode: e.serverResponseCode,
      });
    }

    if (error instanceof Error) {
      const msg = error.message.toLowerCase();
      const errorCode = (error as NodeJS.ErrnoException).code?.toLowerCase() || '';
      const e = error as any;

      // ImapFlow-spezifische Details durchreichen wenn vorhanden
      if (e.authenticationFailed) {
        throw new Error(
          `IMAP-Authentifizierung fehlgeschlagen${e.response ? `: ${e.response}` : ''}`,
        );
      }
      if (e.response || e.responseText) {
        throw new Error(
          `IMAP ${e.responseStatus || 'Fehler'}: ${e.response || e.responseText}`,
        );
      }

      if (msg.includes('authentication') || msg.includes('login')) {
        throw new Error('IMAP-Authentifizierung fehlgeschlagen');
      }
      if (msg.includes('econnrefused') || errorCode === 'econnrefused') {
        throw new Error(`IMAP-Server nicht erreichbar: ${credentials.host}:${credentials.port} - Verbindung verweigert`);
      }
      if (msg.includes('timeout') || msg.includes('etimedout') || errorCode === 'etimedout') {
        if (encryption === 'STARTTLS' && credentials.port === 143) {
          throw new Error(`IMAP Port 143 (STARTTLS) nicht erreichbar auf ${credentials.host}`);
        } else if (encryption === 'SSL' && credentials.port === 993) {
          throw new Error(`IMAP Port 993 (SSL) nicht erreichbar auf ${credentials.host}`);
        } else {
          throw new Error(`IMAP-Verbindung zu ${credentials.host}:${credentials.port} fehlgeschlagen - Timeout`);
        }
      }
      if (msg.includes('certificate') || msg.includes('cert')) {
        throw new Error('IMAP SSL-Zertifikatfehler - Aktiviere "Selbstsignierte Zertifikate erlauben"');
      }
    }

    throw error;
  }
}

// Höchste UID in einer Mailbox ermitteln (für inkrementellen Sync)
export async function getHighestUid(
  credentials: ImapCredentials,
  folder: string = 'INBOX'
): Promise<number> {
  // Verschlüsselungs-Einstellungen basierend auf Modus
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();
    const mailbox = await client.mailboxOpen(folder);
    const highestUid = mailbox.uidNext ? mailbox.uidNext - 1 : 0;
    await client.logout();
    return highestUid;
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }
    throw error;
  }
}

// Anhang-Interface
export interface EmailAttachmentData {
  filename: string;
  content: Buffer;
  contentType: string;
  size: number;
}

// Anhang einer E-Mail per UID abrufen
export async function fetchAttachment(
  credentials: ImapCredentials,
  uid: number,
  attachmentFilename: string,
  folder: string = 'INBOX'
): Promise<EmailAttachmentData | null> {
  // Bei transienten Netzwerkfehlern automatisch bis zu 2x retry
  let lastError: unknown;
  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      return await fetchAttachmentInner(credentials, uid, attachmentFilename, folder);
    } catch (err) {
      lastError = err;
      const msg = err instanceof Error ? err.message.toLowerCase() : '';
      const isTransient =
        msg.includes('socket disconnected') ||
        msg.includes('econnreset') ||
        msg.includes('etimedout') ||
        msg.includes('socket hang up') ||
        msg.includes('network socket');

      if (!isTransient || attempt === 3) {
        throw err;
      }

      console.warn(
        `[fetchAttachment] Versuch ${attempt}/3 fehlgeschlagen (transient), retry in ${attempt * 500}ms:`,
        msg,
      );
      await new Promise((r) => setTimeout(r, attempt * 500));
    }
  }
  throw lastError;
}

async function fetchAttachmentInner(
  credentials: ImapCredentials,
  uid: number,
  attachmentFilename: string,
  folder: string = 'INBOX'
): Promise<EmailAttachmentData | null> {
  // Verschlüsselungs-Einstellungen basierend auf Modus
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
    // Timeouts gegen hängende Verbindungen
    socketTimeout: 30000,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  console.log(`[fetchAttachment] Host: ${credentials.host}:${credentials.port} | User: ${credentials.user} | Folder: ${folder} | UID: ${uid} | File: ${attachmentFilename} | AllowSelfSigned: ${credentials.allowSelfSignedCerts}`);

  try {
    await client.connect();

    // Ordner öffnen – bei Fehler alle verfügbaren Ordner listen für Debugging
    try {
      await client.mailboxOpen(folder);
    } catch (folderErr) {
      console.error(`[fetchAttachment] mailboxOpen('${folder}') failed:`, folderErr);
      try {
        const list = await client.list();
        const available = list.map((m) => m.path).join(', ');
        console.error(`[fetchAttachment] Verfügbare Ordner: ${available}`);
        throw new Error(
          `Ordner '${folder}' nicht gefunden. Verfügbar: ${available}`,
        );
      } catch (listErr) {
        throw folderErr;
      }
    }

    // E-Mail per UID abrufen
    let attachment: EmailAttachmentData | null = null;
    let foundMessage = false;

    // Drittes Argument { uid: true } sorgt dafür, dass UID FETCH statt FETCH verwendet wird
    try {
      for await (const message of client.fetch(uid.toString(), {
        source: true,
      }, { uid: true })) {
        foundMessage = true;
        if (!message.source) continue;

        // E-Mail parsen
        const parsed = await simpleParser(message.source);

        // Anhang suchen
        if (parsed.attachments) {
          for (const att of parsed.attachments) {
            const filename = att.filename || 'unnamed';
            if (filename === attachmentFilename) {
              attachment = {
                filename,
                content: att.content,
                contentType: att.contentType || 'application/octet-stream',
                size: att.size,
              };
              break;
            }
          }
        }
      }
    } catch (fetchErr) {
      // imapflow wirft bei IMAP-NO/BAD immer nur `new Error('Command failed')`,
      // die eigentliche Server-Antwort steht in `.responseText`. Zentraler
      // Helper `humanizeImapError` sorgt dafür, dass Anhang-Download UND
      // Sync die gleiche klare Meldung liefern (2026-07-11: Ursache war
      // ein abgelaufenes Postfach-Passwort, kam als "Command failed" durch).
      console.error(`[fetchAttachment] fetch(UID ${uid}) failed:`, fetchErr);
      throw new Error(
        `Nachricht mit UID ${uid}: ${humanizeImapError(fetchErr)}`,
      );
    }

    if (!foundMessage) {
      console.warn(`[fetchAttachment] Keine Nachricht mit UID ${uid} in Ordner '${folder}' gefunden`);
    }

    await client.logout();
    return attachment;
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }
    throw error;
  }
}

// Gesendete E-Mail im IMAP Sent-Ordner speichern (für Attachment-Download)
export interface AppendToSentParams {
  rawEmail: Buffer | string;  // RFC 5322 formatierte E-Mail
  sentFolder?: string;        // Standard: 'Sent'
}

export interface AppendToSentResult {
  success: boolean;
  uid?: number;      // UID der gespeicherten Nachricht
  error?: string;
}

export async function appendToSent(
  credentials: ImapCredentials,
  params: AppendToSentParams
): Promise<AppendToSentResult> {
  const { rawEmail, sentFolder = 'Sent' } = params;
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  console.log(`[IMAP] Appending email to ${sentFolder} folder...`);

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();

    // E-Mail im Sent-Ordner speichern
    const result = await client.append(sentFolder, rawEmail, ['\\Seen'], new Date());

    await client.logout();

    // append kann false zurückgeben bei Fehler
    if (!result) {
      return { success: false, error: 'IMAP append fehlgeschlagen' };
    }

    console.log(`[IMAP] Email appended successfully, UID: ${result.uid}`);

    return {
      success: true,
      uid: result.uid,
    };
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    console.error('[IMAP] Error appending to Sent folder:', error);

    // Versuche mit alternativen Ordnernamen falls 'Sent' nicht existiert
    if (sentFolder === 'Sent' && error instanceof Error) {
      // Typische alternative Namen für Sent-Ordner
      const alternativeNames = ['INBOX.Sent', 'Sent Messages', 'Sent Items'];

      for (const altFolder of alternativeNames) {
        try {
          const altClient = new ImapFlow(clientOptions);
          await altClient.connect();
          const altResult = await altClient.append(altFolder, rawEmail, ['\\Seen'], new Date());
          await altClient.logout();

          if (altResult) {
            console.log(`[IMAP] Email appended to ${altFolder}, UID: ${altResult.uid}`);
            return { success: true, uid: altResult.uid };
          }
        } catch {
          // Nächsten Namen versuchen
        }
      }
    }

    return {
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Speichern im Sent-Ordner',
    };
  }
}

// Alle Anhänge einer E-Mail per UID abrufen (Metadaten)
export async function fetchAttachmentList(
  credentials: ImapCredentials,
  uid: number,
  folder: string = 'INBOX'
): Promise<Array<{ filename: string; contentType: string; size: number }>> {
  // Verschlüsselungs-Einstellungen basierend auf Modus
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);
  const attachments: Array<{ filename: string; contentType: string; size: number }> = [];

  try {
    await client.connect();
    await client.mailboxOpen(folder);

    // Drittes Argument { uid: true } für UID FETCH
    for await (const message of client.fetch(uid.toString(), {
      source: true,
    }, { uid: true })) {
      if (!message.source) continue;

      const parsed = await simpleParser(message.source);

      if (parsed.attachments) {
        for (const att of parsed.attachments) {
          attachments.push({
            filename: att.filename || 'unnamed',
            contentType: att.contentType || 'application/octet-stream',
            size: att.size,
          });
        }
      }
    }

    await client.logout();
    return attachments;
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }
    throw error;
  }
}

// ==================== TRASH OPERATIONS ====================

// Typische Namen für Trash-Ordner (verschiedene Server/Sprachen)
const TRASH_FOLDER_NAMES = ['Trash', 'INBOX.Trash', 'Deleted', 'Deleted Items', 'Deleted Messages', 'Papierkorb'];

// Übliche Namen für den Spam-/Junk-Ordner (Plesk/Dovecot: "Junk").
const JUNK_FOLDER_NAMES = ['Junk', 'INBOX.Junk', 'Spam', 'INBOX.Spam', 'Junk E-mail', 'Junk Email', 'Bulk Mail'];

// Helper: Trash-Ordner finden
async function findTrashFolder(client: ImapFlow): Promise<string | null> {
  const mailboxes = await client.list();

  for (const name of TRASH_FOLDER_NAMES) {
    const found = mailboxes.find(m =>
      m.path.toLowerCase() === name.toLowerCase() ||
      m.name.toLowerCase() === name.toLowerCase()
    );
    if (found) return found.path;
  }

  // Suche nach Ordner mit \Trash Flag
  const trashByFlag = mailboxes.find(m => m.specialUse === '\\Trash');
  if (trashByFlag) return trashByFlag.path;

  return null;
}

/**
 * Ermittelt den tatsächlichen Pfad des Spam-/Junk-Ordners eines Postfachs.
 * Bevorzugt das IMAP-Special-Use-Flag \Junk, fällt sonst auf übliche
 * Ordnernamen zurück. Öffnet eine eigene Verbindung; gibt null zurück,
 * wenn kein Junk-Ordner existiert (dann wird Spam einfach nicht synct).
 */
export async function findJunkFolderPath(credentials: ImapCredentials): Promise<string | null> {
  const encryption = credentials.encryption ?? 'SSL';
  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: { user: credentials.user, pass: credentials.password },
    logger: false,
  };
  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);
  try {
    await client.connect();
    const mailboxes = await client.list();
    // Zuerst per Special-Use-Flag \Junk
    const byFlag = mailboxes.find(m => m.specialUse === '\\Junk');
    if (byFlag) return byFlag.path;
    // Sonst per Namensliste
    for (const name of JUNK_FOLDER_NAMES) {
      const found = mailboxes.find(m =>
        m.path.toLowerCase() === name.toLowerCase() ||
        m.name.toLowerCase() === name.toLowerCase()
      );
      if (found) return found.path;
    }
    return null;
  } catch {
    return null;
  } finally {
    try { await client.logout(); } catch { /* ignore */ }
  }
}

export interface MoveToTrashResult {
  success: boolean;
  newUid?: number;    // UID im Trash-Ordner
  error?: string;
}

// E-Mail in Papierkorb verschieben
export async function moveToTrash(
  credentials: ImapCredentials,
  uid: number,
  sourceFolder: string = 'INBOX'
): Promise<MoveToTrashResult> {
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();

    // Trash-Ordner finden
    const trashFolder = await findTrashFolder(client);
    if (!trashFolder) {
      await client.logout();
      return { success: false, error: 'Trash-Ordner nicht gefunden' };
    }

    // Source-Ordner öffnen
    await client.mailboxOpen(sourceFolder);

    // E-Mail verschieben (kopieren + löschen)
    const moveResult = await client.messageMove([uid], trashFolder, { uid: true });

    await client.logout();

    if (moveResult && moveResult.uidMap) {
      // uidMap ist Map<number, number> - alte UID -> neue UID
      const newUid = moveResult.uidMap.get(uid);
      console.log(`[IMAP] Email moved to ${trashFolder}, new UID: ${newUid}`);
      return { success: true, newUid };
    }

    return { success: true };
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    console.error('[IMAP] Error moving to trash:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Verschieben in Papierkorb',
    };
  }
}

export interface RestoreFromTrashResult {
  success: boolean;
  newUid?: number;    // UID im wiederhergestellten Ordner
  error?: string;
}

// E-Mail aus Papierkorb wiederherstellen
export async function restoreFromTrash(
  credentials: ImapCredentials,
  uid: number,
  targetFolder: string = 'INBOX'
): Promise<RestoreFromTrashResult> {
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();

    // Trash-Ordner finden
    const trashFolder = await findTrashFolder(client);
    if (!trashFolder) {
      await client.logout();
      return { success: false, error: 'Trash-Ordner nicht gefunden' };
    }

    // Trash-Ordner öffnen
    await client.mailboxOpen(trashFolder);

    // E-Mail zurück verschieben
    const moveResult = await client.messageMove([uid], targetFolder, { uid: true });

    await client.logout();

    if (moveResult && moveResult.uidMap) {
      const newUid = moveResult.uidMap.get(uid);
      console.log(`[IMAP] Email restored to ${targetFolder}, new UID: ${newUid}`);
      return { success: true, newUid };
    }

    return { success: true };
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    console.error('[IMAP] Error restoring from trash:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Wiederherstellen',
    };
  }
}

export interface PermanentDeleteResult {
  success: boolean;
  error?: string;
}

// E-Mail endgültig löschen (aus Trash-Ordner)
export async function permanentDelete(
  credentials: ImapCredentials,
  uid: number,
  folder?: string  // Optional: Ordner angeben, sonst wird Trash verwendet
): Promise<PermanentDeleteResult> {
  const encryption = credentials.encryption ?? 'SSL';
  const rejectUnauthorized = !credentials.allowSelfSignedCerts;

  const clientOptions: ConstructorParameters<typeof ImapFlow>[0] = {
    host: credentials.host,
    port: credentials.port,
    secure: encryption === 'SSL',
    auth: {
      user: credentials.user,
      pass: credentials.password,
    },
    logger: false,
  };

  if (encryption !== 'NONE') {
    const __tls = buildTlsOptions(credentials); if (__tls) clientOptions.tls = __tls as any;
  }

  const client = new ImapFlow(clientOptions);

  try {
    await client.connect();

    // Ordner bestimmen
    let targetFolder: string | null | undefined = folder;
    if (!targetFolder) {
      targetFolder = await findTrashFolder(client);
      if (!targetFolder) {
        await client.logout();
        return { success: false, error: 'Trash-Ordner nicht gefunden' };
      }
    }

    // Ordner öffnen
    await client.mailboxOpen(targetFolder);

    // E-Mail als gelöscht markieren und expunge
    await client.messageDelete([uid], { uid: true });

    await client.logout();

    console.log(`[IMAP] Email permanently deleted from ${targetFolder}, UID: ${uid}`);
    return { success: true };
  } catch (error) {
    try {
      await client.logout();
    } catch {
      // Ignorieren
    }

    console.error('[IMAP] Error permanently deleting:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim endgültigen Löschen',
    };
  }
}
