import { prisma } from "@/lib/prisma";
import { notifyAdmins } from "@/lib/admin-notify";

/**
 * Wrapper untuk cron route handler — otomatis log start/finish/error ke
 * `CronRun`. Idempotent terhadap kegagalan: kalau row gagal dibuat (DB down),
 * fn tetap jalan dan kegagalannya hanya hilang log.
 *
 * Pemakaian:
 * ```ts
 * return runCron("auto-complete-trips", async () => {
 *   const result = await tripService.autoCompletePastTrips();
 *   return { completed: result.count, ids: result.ids };
 * });
 * ```
 *
 * Caller bertanggung jawab untuk mengembalikan NextResponse — `runCron`
 * cuma menjalankan fn dan log; return value fn dipassthrough sebagai `payload`.
 */
export async function runCron<T>(
  jobName: string,
  fn: () => Promise<T>
): Promise<{ ok: true; payload: T } | { ok: false; error: string }> {
  let runId: string | null = null;
  try {
    const row = await prisma.cronRun.create({
      data: { jobName, status: "RUNNING" },
      select: { id: true },
    });
    runId = row.id;
  } catch (err) {
    console.error(`[cron-runner] gagal create row ${jobName}`, err);
    // Lanjut tanpa log — jangan blok cron karena DB log gagal.
  }

  try {
    const payload = await fn();
    if (runId) {
      await prisma.cronRun
        .update({
          where: { id: runId },
          data: {
            status: "SUCCESS",
            finishedAt: new Date(),
            payload: payload as unknown as object,
          },
        })
        .catch((e) => console.error(`[cron-runner] gagal update SUCCESS`, e));
    }
    return { ok: true, payload };
  } catch (err) {
    const message =
      err instanceof Error ? err.message : "Unknown cron failure";
    if (runId) {
      await prisma.cronRun
        .update({
          where: { id: runId },
          data: {
            status: "FAILED",
            finishedAt: new Date(),
            errorMessage: message,
          },
        })
        .catch((e) => console.error(`[cron-runner] gagal update FAILED`, e));
    }
    // Fire-and-forget — jangan blok response cron route handler. Notif gagal
    // di-log sendiri di `notifyAdmins`.
    void notifyAdmins(
      `Cron \`${jobName}\` FAILED: ${message}`
    );
    return { ok: false, error: message };
  }
}
