import { ImapFlow } from "imapflow";
import {
  getMailConnections,
  deleteOldMailBlocked,
  getAlreadyBlockedUidSet,
  insertMailBlocked,
  updateMailConnectionScanStats,
} from "../../db/mail";
import { getBlocklistedDomainsSet } from "../../db/domains";
import { getProfile } from "../../db/profile";
import { getPlanLimits } from "../../utils/plan-features";
// Single-Source-of-Truth (Mo's Finding #4)
// @ts-expect-error — .mjs ohne types, GAMBLING_KEYWORDS ist string[]
import { GAMBLING_KEYWORDS } from "../../utils/gambling-keywords.mjs";


/**
 * POST /api/mail/scan
 * Scannt ALLE Ordner (INBOX, Spam, Papierkorb, All Mail …) nach Gambling-Mails.
 * Free-User: nur eigene Domains + Keywords. Pro/Legend: globale Blocklist + eigene.
 */
export default defineEventHandler(async (event) => {
  const user = await requireUser(event);

  const connections = await getMailConnections(user.id);
  if (connections.length === 0) {
    throw createError({
      statusCode: 404,
      message: "Kein Mail-Konto verbunden",
    });
  }

  // Plan-aware: Free users get only custom domains, Pro/Legend get global blocklist
  const profile = await getProfile(user.id);
  const limits = getPlanLimits(profile?.plan ?? "free");
  const includeGlobal = limits.globalBlocklist;

  await deleteOldMailBlocked(user.id);

  let totalScanned = 0;
  let totalBlocked = 0;

  for (const connection of connections) {
    let password: string;
    try {
      password = decrypt(connection.passwordEncrypted);
    } catch {
      continue;
    }

    // useStarttls=true → STARTTLS (secure=false + requireTLS=true)
    // rejectUnauthorized=false → self-signed Certs zulassen (nur Custom-IMAP)
    const useImplicitTls = !connection.useStarttls;
    const imap = new ImapFlow({
      host: connection.imapHost,
      port: connection.imapPort,
      secure: useImplicitTls,
      ...(connection.useStarttls ? { requireTLS: true } : {}),
      auth: { user: connection.email, pass: password },
      logger: false,
      tls: { rejectUnauthorized: connection.rejectUnauthorized ?? true },
    });

    let scanned = 0;
    let newlyBlocked = 0;

    try {
      await imap.connect();

      // Scan ALL mailbox folders (not just hardcoded list)
      const mailboxes = await imap.list();
      const scannable = mailboxes.filter(
        (mb: any) => !mb.flags?.has("\\Noselect"),
      );

      for (const mb of scannable) {
        let lock: any;
        try {
          lock = await imap.getMailboxLock(mb.path);
        } catch {
          continue;
        }
        try {
          const SCAN_LIMIT = 200;
          const status = await imap.status(mb.path, { messages: true });
          const msgCount = (status as any).messages ?? 0;
          if (msgCount === 0) continue;

          const fetchRange =
            msgCount > SCAN_LIMIT ? `${msgCount - SCAN_LIMIT + 1}:*` : "1:*";
          const allMessages = await imap.fetchAll(fetchRange, {
            envelope: true,
          });
          scanned += allMessages.length;
          totalScanned += allMessages.length;

          const allUids = allMessages.map(
            (m: any) => `${mb.path}:${String(m.uid ?? m.seq)}`,
          );
          const [blockedDomainSet, alreadyBlockedSet] = await Promise.all([
            getBlocklistedDomainsSet(
              allMessages
                .map(
                  (m: any) =>
                    (m.envelope?.from?.[0]?.address ?? "")
                      .toLowerCase()
                      .split("@")[1] ?? "",
                )
                .filter(Boolean),
              user.id,
              includeGlobal,
            ),
            getAlreadyBlockedUidSet(allUids, user.id),
          ]);

          const toInsert: Parameters<typeof insertMailBlocked>[0] = [];
          const uidsToDelete: string[] = [];

          for (const msg of allMessages) {
            const from = msg.envelope?.from?.[0];
            const senderEmail = (from?.address ?? "").toLowerCase();
            const senderName = from?.name ?? null;
            const subject = (msg.envelope?.subject ?? "").trim();
            const msgDate = msg.envelope?.date ?? new Date();
            const uid = `${mb.path}:${String(msg.uid ?? msg.seq)}`;

            const haystack = `${senderEmail} ${subject}`.toLowerCase();
            const isGamblingKeyword = GAMBLING_KEYWORDS.some((kw) =>
              haystack.includes(kw),
            );
            const senderDomain = senderEmail.split("@")[1] ?? "";
            const isBlocklisted = senderDomain
              ? blockedDomainSet.has(senderDomain)
              : false;

            if (!isGamblingKeyword && !isBlocklisted) continue;
            if (alreadyBlockedSet.has(uid)) continue;

            uidsToDelete.push(String(msg.uid));
            toInsert.push({
              userId: user.id,
              connectionId: connection.id,
              gmailMessageId: uid,
              senderEmail: senderEmail || "unbekannt",
              senderName,
              subject: subject.slice(0, 200) || "(kein Betreff)",
              receivedAt: msgDate,
              action: "deleted",
            });
            newlyBlocked++;
          }

          // Permanently delete gambling mails from this folder
          if (uidsToDelete.length > 0) {
            try {
              await imap.messageDelete(uidsToDelete.join(","), { uid: true });
            } catch {
              try {
                for (const uid of uidsToDelete) {
                  await imap
                    .messageFlagsAdd(uid, ["\\Deleted"], { uid: true })
                    .catch(() => {});
                }
                await imap.expunge();
              } catch {
                /* ignore */
              }
            }
          }

          await insertMailBlocked(toInsert);
        } finally {
          lock.release();
        }
      }

      await imap.logout();
    } catch {
      try {
        await imap.logout();
      } catch {}
    }

    totalBlocked += newlyBlocked;
    await updateMailConnectionScanStats(
      connection.id,
      scanned,
      newlyBlocked,
      connection.emailsBlocked,
      connection.emailsScanned,
      connection.scanInterval,
    );
  }

  return { scanned: totalScanned, blocked: totalBlocked };
});
