/**
 * Mail-Retention-Cron — Phase 1 Data-Foundation.
 *
 * Zweck: DSGVO-konforme Datensparsamkeit (Art. 5 Abs. 1e — Speicherbegrenzung)
 *        + Disk-Budget-Kontrolle (Staging + Prod).
 *
 * Drei Retention-Jobs:
 *
 *   1. Subject-Nullification (täglich):
 *      Raw-Subject auf null setzen wenn älter als 30 Tage. Das sanitisierte
 *      Subject (features.subjectSanitized) bleibt erhalten.
 *
 *   2. Sample-Purge (monatlich):
 *      Samples älter als 12 Monate hart löschen (für LLM-Training irrelevant).
 *      User-Lösch-Recht (Art. 17) → deleteUserMailClassificationSamples().
 *
 *   3. Row-Cap (täglich):
 *      Hält die Tabelle auf MAX_SAMPLE_ROWS. Löscht älteste Rows wenn Cap
 *      überschritten. Verhindert unbegrenztes Disk-Wachstum (Staging + Prod).
 *      Cap = 100k Rows ≈ ~500MB bei durchschnittlicher Row-Größe.
 *
 * Läuft nur in Production (import.meta.dev guard).
 * Alle Jobs laufen beim Server-Start einmalig + dann periodisch.
 */

import { consola } from "consola";
import { usePrisma } from "../utils/prisma";

// Subject-Nullification: täglich
const SUBJECT_NULLIFY_INTERVAL_MS = 24 * 60 * 60 * 1000;
const SUBJECT_NULLIFY_AGE_DAYS = 30;

// Sample-Purge: alle 30 Tage (monatlich)
const SAMPLE_PURGE_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000;
const SAMPLE_PURGE_AGE_DAYS = 365;

// Row-Cap: täglich — hält Tabelle unter diesem Limit
const ROW_CAP_INTERVAL_MS = 24 * 60 * 60 * 1000;
const MAX_SAMPLE_ROWS = 100_000;

export default defineNitroPlugin((nitro) => {
  if (import.meta.dev) return;

  consola.info("[mail-retention-cron] Starting — subject-nullify daily, sample-purge monthly, row-cap daily");

  void runSubjectNullification().catch(() => {});
  void runSamplePurge().catch(() => {});
  void runRowCap().catch(() => {});

  const nullifyInterval = setInterval(() => {
    void runSubjectNullification().catch(() => {});
  }, SUBJECT_NULLIFY_INTERVAL_MS);

  const purgeInterval = setInterval(() => {
    void runSamplePurge().catch(() => {});
  }, SAMPLE_PURGE_INTERVAL_MS);

  const capInterval = setInterval(() => {
    void runRowCap().catch(() => {});
  }, ROW_CAP_INTERVAL_MS);

  nitro.hooks.hook("close", () => {
    clearInterval(nullifyInterval);
    clearInterval(purgeInterval);
    clearInterval(capInterval);
  });
});

/**
 * Setzt raw-Subject-Feld auf null für Samples älter als 30 Tage.
 * features.subjectSanitized bleibt erhalten (wurde bei Insert geschrieben).
 *
 * Verwendet $executeRaw weil Prisma updateMany kein
 * WHERE subject IS NOT NULL direkt unterstützt (kein affected-rows-count).
 */
async function runSubjectNullification(): Promise<void> {
  const db = usePrisma();
  const cutoff = new Date(Date.now() - SUBJECT_NULLIFY_AGE_DAYS * 86_400_000);

  const result = await db.$executeRaw`
    UPDATE "rebreak"."mail_classification_samples"
    SET "subject" = NULL
    WHERE "subject" IS NOT NULL
      AND "created_at" < ${cutoff}::timestamptz
  `;

  if (result > 0) {
    consola.info(`[mail-retention-cron] subject-nullify: ${result} samples anonymized`);
  }
}

/**
 * Löscht MailClassificationSamples älter als 12 Monate.
 */
async function runSamplePurge(): Promise<void> {
  const db = usePrisma();
  const cutoff = new Date(Date.now() - SAMPLE_PURGE_AGE_DAYS * 86_400_000);

  const result = await db.mailClassificationSample.deleteMany({
    where: { createdAt: { lt: cutoff } },
  });

  if (result.count > 0) {
    consola.info(`[mail-retention-cron] sample-purge: ${result.count} old samples deleted`);
  }
}

/**
 * Row-Cap: hält mail_classification_samples unter MAX_SAMPLE_ROWS.
 *
 * Löscht älteste Rows wenn der Cap überschritten wird. Nutzt einen
 * CTE-basierten Delete der nur einen Index-Scan braucht (created_at INDEX).
 * Kein Full-Table-Scan — auch auf großen Tabellen effizient.
 */
async function runRowCap(): Promise<void> {
  const db = usePrisma();

  const count = await db.mailClassificationSample.count();
  if (count <= MAX_SAMPLE_ROWS) return;

  const toDelete = count - MAX_SAMPLE_ROWS;

  // Löscht die `toDelete` ältesten Rows via Subquery auf created_at-Index.
  const result = await db.$executeRaw`
    DELETE FROM "rebreak"."mail_classification_samples"
    WHERE "id" IN (
      SELECT "id"
      FROM "rebreak"."mail_classification_samples"
      ORDER BY "created_at" ASC
      LIMIT ${toDelete}
    )
  `;

  consola.info(`[mail-retention-cron] row-cap: ${result} samples pruned (cap=${MAX_SAMPLE_ROWS}, was=${count})`);
}
