import { logError, logInfo } from "@/lib/logger";
import { ExportRequestsRepository } from "@/internal/repository/admin_console/export_requests";
import { ExportStorage } from "@/lib/storage/export-storage";
import type { Kysely } from "kysely";

/**
 * Deletes delivered export workbooks from GCS once they are a day old.
 *
 * An approved export has already been emailed to the requester, so the copy in the
 * bucket is only there for a short grace period — long enough to re-download from the
 * queue if the mail bounced or was deleted. After that it is member data sitting in
 * storage for no reason, so it goes.
 *
 * Driven by database state rather than a timer set at approval: the process restarts,
 * deploys happen, and a scheduled in-memory deletion would simply be lost. Asking
 * "which delivered files are older than the window" is answerable at any moment, from
 * any instance, which also makes the job safe to run more than once.
 */

/** How long a delivered file stays downloadable from the queue. */
export const EXPORT_FILE_TTL_HOURS = 24;

/**
 * Files handled per pass.
 *
 * Each one is a network round-trip to GCS, so a backlog is worked through over
 * several runs instead of one long pass holding the loop open.
 */
const BATCH_SIZE = 100;

export async function purgeDeliveredExportFiles(
  db: Kysely<any>,
): Promise<void> {
  try {
    const cutoff = new Date(
      Date.now() - EXPORT_FILE_TTL_HOURS * 60 * 60 * 1000,
    );
    const repo = new ExportRequestsRepository(db);
    const due = await repo.findPurgeableFiles(cutoff, BATCH_SIZE);
    if (due.length === 0) return;

    const storage = ExportStorage();
    let purged = 0;

    for (const row of due) {
      try {
        /*
         * Delete the object, then record it.
         *
         * `deleteWorkbook` ignores a missing object and never throws, so a file
         * already removed by hand or by a bucket lifecycle rule still gets its row
         * marked instead of being retried on every pass forever.
         */
        await storage.deleteWorkbook(row.file_path);
        await repo.markFilePurged(row.id);
        purged += 1;
      } catch (rowErr: any) {
        // One stuck row must not stop the rest of the batch; the next pass retries it.
        logError(
          `[ExportFilePurge] Failed purging ${row.file_path} for request ${row.id}: ${rowErr?.message ?? rowErr}`,
        );
      }
    }

    if (purged > 0) {
      logInfo(
        `[ExportFilePurge] Deleted ${purged} export file(s) delivered before ${cutoff.toISOString()}.`,
      );
    }
  } catch (err: any) {
    logError(
      `[ExportFilePurge] purgeDeliveredExportFiles error: ${err?.message ?? err}`,
    );
  }
}
