/**
 * Tests: Gmail-Delete-Strategie — MOVE statt EXPUNGE
 *
 * scan-internal.post.ts wählt den Delete-Pfad anhand des IMAP-Hosts:
 *   - imap.gmail.com  → messageMove() in Trash-Folder (MOVE)
 *   - alle anderen    → messageDelete() + EXPUNGE-Fallback
 *
 * Diese Tests validieren die Auswahllogik als Pure-Logic-Unit,
 * ohne echten IMAP-Connect. Mock-IMAP simuliert Aufrufverhalten.
 *
 * DSGVO: keine PII. Synthetic User-IDs (uuid-Format), keine echten E-Mails.
 */
import { describe, it, expect, vi } from "vitest";

// ─── Mock-IMAP-Factory ────────────────────────────────────────────────────────

function makeImapMock({
  trashSpecialUsePath,
}: {
  trashSpecialUsePath?: string;
} = {}) {
  const mailboxes = [
    { path: "INBOX", flags: new Set<string>(), specialUse: undefined },
    {
      path: trashSpecialUsePath ?? "[Gmail]/Trash",
      flags: new Set<string>(),
      specialUse: "\\Trash",
    },
    { path: "[Gmail]/All Mail", flags: new Set<string>(), specialUse: "\\All" },
  ];

  return {
    connect: vi.fn().mockResolvedValue(undefined),
    logout: vi.fn().mockResolvedValue(undefined),
    list: vi.fn().mockResolvedValue(mailboxes),
    getMailboxLock: vi.fn().mockResolvedValue({ release: vi.fn() }),
    status: vi.fn().mockResolvedValue({ messages: 0 }),
    fetchAll: vi.fn().mockResolvedValue([]),
    messageMove: vi.fn().mockResolvedValue(undefined),
    messageDelete: vi.fn().mockResolvedValue(undefined),
    messageFlagsAdd: vi.fn().mockResolvedValue(undefined),
    expunge: vi.fn().mockResolvedValue(undefined),
    _mailboxes: mailboxes,
  };
}

// ─── Auswahllogik als Pure Function (extrahiert aus scan-internal) ────────────
//
// Die eigentliche Logik sitzt in scan-internal.post.ts welches Nitro-Globals
// braucht und daher nicht direkt importiert werden kann. Wir testen die
// Entscheidungslogik als isolierte Funktion — identisch zum Produktionscode.

type MailboxEntry = { path: string; specialUse?: string };

function resolveTrashFolder(mailboxes: MailboxEntry[]): string {
  const trashMailbox = mailboxes.find((mb) => mb.specialUse === "\\Trash");
  return trashMailbox?.path ?? "[Gmail]/Trash";
}

async function performDelete(opts: {
  isGmail: boolean;
  uids: string[];
  imap: ReturnType<typeof makeImapMock>;
  mailboxes: MailboxEntry[];
}): Promise<void> {
  const { isGmail, uids, imap, mailboxes } = opts;
  if (uids.length === 0) return;

  if (isGmail) {
    const trashFolder = resolveTrashFolder(mailboxes);
    await imap.messageMove(uids.join(","), trashFolder, { uid: true });
  } else {
    await imap.messageDelete(uids.join(","), { uid: true });
  }
}

// ─── Tests ────────────────────────────────────────────────────────────────────

describe("Gmail-Delete-Strategie: MOVE statt EXPUNGE", () => {
  it("Gmail-Host → messageMove() wird gerufen, messageDelete() NICHT", async () => {
    const imap = makeImapMock();

    await performDelete({
      isGmail: true,
      uids: ["42", "43"],
      imap,
      mailboxes: imap._mailboxes,
    });

    expect(imap.messageMove).toHaveBeenCalledOnce();
    expect(imap.messageDelete).not.toHaveBeenCalled();
  });

  it("Gmail: MOVE wird mit korrekten UIDs gerufen (komma-separiert)", async () => {
    const imap = makeImapMock();

    await performDelete({
      isGmail: true,
      uids: ["10", "11", "12"],
      imap,
      mailboxes: imap._mailboxes,
    });

    expect(imap.messageMove).toHaveBeenCalledWith("10,11,12", expect.any(String), { uid: true });
  });

  it("Gmail mit specialUse='\\\\Trash' → Trash-Pfad via specialUse aufgelöst (kein Hardcode)", async () => {
    // Simuliert deutschen Gmail: Trash heißt '[Gmail]/Papierkorb'
    const imap = makeImapMock({ trashSpecialUsePath: "[Gmail]/Papierkorb" });

    await performDelete({
      isGmail: true,
      uids: ["99"],
      imap,
      mailboxes: imap._mailboxes,
    });

    const [, targetFolder] = imap.messageMove.mock.calls[0];
    expect(targetFolder).toBe("[Gmail]/Papierkorb");
  });

  it("Gmail ohne specialUse='\\\\Trash' in Mailbox-Liste → Fallback '[Gmail]/Trash'", async () => {
    // Edge-Case: kein Mailbox mit specialUse='\\Trash' vorhanden
    const mailboxesNoTrash: MailboxEntry[] = [
      { path: "INBOX", specialUse: undefined },
      { path: "[Gmail]/All Mail", specialUse: "\\All" },
    ];
    const imap = makeImapMock();

    await performDelete({
      isGmail: true,
      uids: ["55"],
      imap,
      mailboxes: mailboxesNoTrash,
    });

    const [, targetFolder] = imap.messageMove.mock.calls[0];
    expect(targetFolder).toBe("[Gmail]/Trash");
  });

  it("Nicht-Gmail (iCloud/Outlook/IONOS) → messageDelete() wird gerufen, messageMove() NICHT", async () => {
    const imap = makeImapMock();

    await performDelete({
      isGmail: false,
      uids: ["1", "2"],
      imap,
      mailboxes: imap._mailboxes,
    });

    expect(imap.messageDelete).toHaveBeenCalledOnce();
    expect(imap.messageMove).not.toHaveBeenCalled();
  });

  it("Leere UIDs → weder MOVE noch DELETE gerufen", async () => {
    const imap = makeImapMock();

    await performDelete({
      isGmail: true,
      uids: [],
      imap,
      mailboxes: imap._mailboxes,
    });

    expect(imap.messageMove).not.toHaveBeenCalled();
    expect(imap.messageDelete).not.toHaveBeenCalled();
  });
});

// ─── resolveTrashFolder() — Unit-Tests ───────────────────────────────────────

describe("resolveTrashFolder()", () => {
  it("Mailbox mit specialUse='\\\\Trash' → deren path wird zurückgegeben", () => {
    const mailboxes: MailboxEntry[] = [
      { path: "INBOX" },
      { path: "[Gmail]/Trash", specialUse: "\\Trash" },
      { path: "[Gmail]/All Mail", specialUse: "\\All" },
    ];
    expect(resolveTrashFolder(mailboxes)).toBe("[Gmail]/Trash");
  });

  it("Deutschen Gmail: '[Gmail]/Papierkorb' als specialUse-Trash", () => {
    const mailboxes: MailboxEntry[] = [
      { path: "INBOX" },
      { path: "[Gmail]/Papierkorb", specialUse: "\\Trash" },
    ];
    expect(resolveTrashFolder(mailboxes)).toBe("[Gmail]/Papierkorb");
  });

  it("Kein Trash-Mailbox → Fallback '[Gmail]/Trash'", () => {
    const mailboxes: MailboxEntry[] = [
      { path: "INBOX" },
      { path: "[Gmail]/All Mail", specialUse: "\\All" },
    ];
    expect(resolveTrashFolder(mailboxes)).toBe("[Gmail]/Trash");
  });

  it("Leere Mailbox-Liste → Fallback '[Gmail]/Trash'", () => {
    expect(resolveTrashFolder([])).toBe("[Gmail]/Trash");
  });
});
