import cron from "node-cron";
import { prisma } from "../lib/db";
import { createLogger } from "../lib/logger";
import { getAdminSettings } from "../lib/adminSettings";

const log = createLogger("CRON");

export function startCronWorkers() {
  // Inactivity check every 5 minutes
  cron.schedule("*/5 * * * *", async () => {
    try {
      await checkInactivity();
    } catch (e) {
      log.error({ e }, "Inactivity check error");
    }
  });

  // Daily cleanup
  cron.schedule("0 3 * * *", async () => {
    try {
      await dailyCleanup();
    } catch (e) {
      log.error({ e }, "Daily cleanup error");
    }
  });

  // Run an inactivity check immediately on startup so previews that went idle
  // while PP was down aren't left waiting for the next scheduled tick.
  checkInactivity().catch((e) => log.error({ e }, "Startup inactivity check error"));

  log.info("Cron workers started");
}

async function checkInactivity() {
  const now = new Date();

  const running = await prisma.preview.findMany({
    where: { status: "RUNNING" },
    include: { repoConfig: { select: { inactivityHours: true } } },
  });

  for (const preview of running) {
    const inactivityHours = preview.repoConfig.inactivityHours;
    const deadline = new Date(preview.lastActivityAt.getTime() + inactivityHours * 3600 * 1000);
    if (now >= deadline) {
      log.info({ previewId: preview.id, inactivityHours }, "Preview inactive, enqueuing INACTIVITY_STOP");
      // Only create one pending INACTIVITY_STOP per preview
      const existingStop = await prisma.job.findFirst({
        where: { previewId: preview.id, type: "INACTIVITY_STOP", status: { in: ["PENDING", "RUNNING"] } },
      });
      if (!existingStop) {
        await prisma.job.create({
          data: {
            previewId: preview.id,
            type: "INACTIVITY_STOP",
            status: "PENDING",
            payload: {},
          },
        });
      }
    }
  }
}

async function dailyCleanup() {
  const settings = await getAdminSettings();
  const cutoff = new Date(Date.now() - settings.previewRetentionDays * 86400 * 1000);

  const old = await prisma.preview.findMany({
    where: {
      status: { in: ["STOPPED", "FAILED"] },
      stoppedAt: { lt: cutoff },
    },
    select: { id: true },
  });

  for (const { id } of old) {
    await prisma.job.deleteMany({ where: { previewId: id } });
    await prisma.preview.delete({ where: { id } });
  }

  if (old.length > 0) log.info({ count: old.length }, "Cleaned up old previews");
}
