import { processDueReminders, scheduleNoShowReminders } from "./reminders";
import { prisma } from "./db";
import { registerMapping } from "./phone-map";

let cronStarted = false;
let lastRun: Date | null = null;
let runCount = 0;
let isRunning = false;

export function getCronStatus() {
  return { lastRun, isRunning, runCount };
}

async function runReminders() {
  const start = Date.now();
  try {
    const results = await processDueReminders();
    const duration = Date.now() - start;
    lastRun = new Date();
    runCount++;

    if (results.sent > 0 || results.failed > 0 || results.skipped > 0) {
      console.log(
        `⏰ Cron: sent=${results.sent}, skipped=${results.skipped}, failed=${results.failed}, retried=${results.retried}`
      );

      try {
        await prisma.cronLog.create({
          data: {
            type: "send-reminders",
            sent: results.sent,
            skipped: results.skipped,
            failed: results.failed,
            retried: results.retried,
            durationMs: duration,
          },
        });
      } catch {
        // Don't crash the cron if logging fails
      }
    }
  } catch (error) {
    const duration = Date.now() - start;
    console.error("⏰ Cron error:", error);

    try {
      await prisma.cronLog.create({
        data: {
          type: "send-reminders",
          durationMs: duration,
          error: error instanceof Error ? error.message : "Unknown error",
        },
      });
    } catch {
      // Don't crash
    }
  }
}

function scheduleReminderInterval() {
  const timer = setInterval(async () => {
    if (isRunning) return;
    isRunning = true;
    try {
      await runReminders();
    } finally {
      isRunning = false;
    }
  }, 30_000);

  // Unref so it doesn't prevent process exit in tests
  if (timer.unref) timer.unref();
}

/**
 * Start an in-process cron that:
 * 1. Checks for due reminders every 30 seconds
 * 2. Auto-detects no-shows every 5 minutes
 *
 * Safe to call multiple times — will only start once.
 * Runs immediately on startup (after 2s DB settle delay) to cover restart gaps.
 * Logs every execution to CronLog for dashboard monitoring.
 */
export function startReminderCron() {
  if (cronStarted) return;
  cronStarted = true;

  // Seed known LID → phone mappings
  registerMapping("274156486697100", "201066544750"); // obaid

  console.log("⏰ Reminder cron started — checking every 30 seconds");
  console.log("⏰ No-show detection started — checking every 5 minutes");

  // ─── Immediate startup run (covers gap after server restart) ───
  setTimeout(async () => {
    console.log("⏰ Cron startup run — processing any missed reminders");
    isRunning = true;
    try {
      await runReminders();
    } finally {
      isRunning = false;
    }
  }, 2_000);

  // ─── Reminder Processing (every 30s) ───
  scheduleReminderInterval();

  // ─── Auto No-Show Detection (every 5 min) ───
  setInterval(async () => {
    try {
      const now = new Date();

      const overdueAppointments = await prisma.appointment.findMany({
        where: {
          status: { in: ["scheduled", "confirmed"] },
          dateTime: {
            lte: new Date(now.getTime() - 60 * 60_000),
          },
        },
        include: { treatment: true, lead: true },
        take: 20,
      });

      let marked = 0;
      for (const apt of overdueAppointments) {
        const expectedEnd = new Date(
          new Date(apt.dateTime).getTime() + (apt.treatment.duration + 30) * 60_000
        );

        if (now > expectedEnd) {
          await prisma.appointment.update({
            where: { id: apt.id },
            data: { status: "no_show" },
          });

          await prisma.lead.update({
            where: { id: apt.leadId },
            data: { status: "no_show" },
          }).catch(() => {});

          await prisma.scheduledReminder.updateMany({
            where: { appointmentId: apt.id, status: "pending" },
            data: { status: "skipped" },
          }).catch(() => {});

          await scheduleNoShowReminders(apt.id).catch((err) =>
            console.error(`⚠️ Failed to schedule no-show reminders for ${apt.id}:`, err)
          );

          marked++;
          console.log(
            `🚫 Auto no-show: ${apt.lead.name} (${apt.treatment.name}) — appointment was at ${new Date(apt.dateTime).toLocaleString()}`
          );
        }
      }

      if (marked > 0) {
        console.log(`🚫 Auto-detected ${marked} no-show${marked > 1 ? "s" : ""}`);
        try {
          await prisma.cronLog.create({
            data: {
              type: "auto-noshow",
              sent: 0,
              skipped: 0,
              failed: marked,
              durationMs: 0,
            },
          });
        } catch { /* ignore */ }
      }
    } catch (error) {
      console.error("🚫 Auto no-show detection error:", error);
    }
  }, 5 * 60_000);
}
