/**
 * GET /api/cron/site-audit-cleanup
 *
 * Re-kicks runs stuck in "crawling" or "processing" for > 15 minutes.
 * Marks as failed any run stuck for > 2 hours (DFS task likely expired).
 * Schedule: every 10 minutes.
 */
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

export const dynamic = "force-dynamic";

const CRON_SECRET = process.env.CRON_SECRET ?? "";
const REKICK_THRESHOLD_MS = 15 * 60 * 1000;
const FAIL_THRESHOLD_MS = 2 * 60 * 60 * 1000;
const MAX_REKICKS_PER_TICK = 3;

function isAuthorized(req: Request): boolean {
  if (!CRON_SECRET) return false;
  const header = req.headers.get("authorization") ?? "";
  if (header === `Bearer ${CRON_SECRET}`) return true;
  return new URL(req.url).searchParams.get("secret") === CRON_SECRET;
}

export async function GET(req: Request) {
  if (!isAuthorized(req)) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const now = Date.now();
  const rekickCutoff = new Date(now - REKICK_THRESHOLD_MS);
  const failCutoff = new Date(now - FAIL_THRESHOLD_MS);
  const origin = new URL(req.url).origin;

  // Mark hopeless runs as failed (> 2 hours old and still in-progress)
  const hopeless = await prisma.siteAuditRun.findMany({
    where: {
      status: { in: ["pending", "crawling", "processing"] },
      createdAt: { lt: failCutoff },
    },
    select: { id: true },
  });
  if (hopeless.length > 0) {
    await prisma.siteAuditRun.updateMany({
      where: { id: { in: hopeless.map((r) => r.id) } },
      data: { status: "failed", errorMessage: "Timed out (> 2 hours)", completedAt: new Date() },
    });
  }

  // Re-kick runs stuck in crawling/processing for > 15 min but < 2 hours
  const stuckRuns = await prisma.siteAuditRun.findMany({
    where: {
      status: { in: ["crawling", "processing"] },
      updatedAt: { lt: rekickCutoff },
      createdAt: { gte: failCutoff },
    },
    select: { id: true, status: true },
  });

  const runsToKick = stuckRuns.slice(0, MAX_REKICKS_PER_TICK);
  const rekicked: string[] = [];
  for (const run of runsToKick) {
    // Refresh updatedAt before firing so a second tick won't re-kick the same run
    // if the /process invocation is still in flight.
    await prisma.siteAuditRun.update({
      where: { id: run.id },
      data: { status: run.status },
    });
    fetch(`${origin}/api/site-audit/${run.id}/process`, {
      method: "POST",
      headers: { authorization: `Bearer ${CRON_SECRET}` },
    }).catch(() => {});
    rekicked.push(run.id);
  }

  console.log(
    `[site-audit-cleanup] failed=${hopeless.length} rekicked=${rekicked.length}`,
  );
  return NextResponse.json({
    failed: hopeless.length,
    rekicked: rekicked.length,
    ids: rekicked,
  });
}
