import { NextResponse } from "next/server";
import { sql } from "@/db";
import { sendAlert } from "@/lib/alert";

/**
 * Monitor cron — catches the failures Uptime Kuma can't see from the outside:
 *   • Error spikes  (rising-edge: last hour vs the hour before)
 *   • DB unreachable
 *   • Migrations missing / integration env not configured
 *
 * Uptime Kuma handles up/down flip detection by pinging /api/healthz, so this
 * focuses on internal signals. Recommended schedule: hourly.
 *
 *   POST/GET /api/cron/monitor        (header: x-cron-secret)
 *   GET      /api/cron/monitor?test=1 — sends a test Telegram ping
 *
 * Stateless by design: error alerts use rising-edge comparison so a sustained
 * (flat) error rate won't re-alert every run — only genuine new spikes do.
 */
export const dynamic = "force-dynamic";

const SPIKE_MIN = 5;        // need at least this many errors in the last hour
const SPIKE_MULTIPLIER = 2; // …and > 2× the previous hour to count as a spike

function authed(request: Request): boolean {
  return request.headers.get("x-cron-secret") === process.env.CRON_SECRET;
}

export async function POST(request: Request) {
  if (!authed(request)) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  return runMonitor(request);
}

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

async function runMonitor(request: Request) {
  const { searchParams } = new URL(request.url);

  // Manual test ping — confirms the Telegram wiring end-to-end.
  if (searchParams.get("test")) {
    const ok = await sendAlert("info", "Monitor test ping", "Telegram alerting is wired correctly. 🎉");
    return NextResponse.json({ ok, test: true });
  }

  const fired: string[] = [];

  // 1. Database reachable?
  try {
    await sql`SELECT 1`;
  } catch (e) {
    await sendAlert("fatal", "Database unreachable", String(e).slice(0, 300));
    return NextResponse.json({ ok: false, dbOk: false, fired: ["db_down"] });
  }

  // 2. Error spike — rising edge (last 1h vs the hour before it)
  let recent = 0;
  let prior = 0;
  try {
    const rows = await sql`
      SELECT
        COUNT(*) FILTER (WHERE created_at >  NOW() - INTERVAL '1 hour')::int AS recent,
        COUNT(*) FILTER (WHERE created_at <= NOW() - INTERVAL '1 hour'
                          AND  created_at >  NOW() - INTERVAL '2 hours')::int AS prior
      FROM error_events
    `;
    recent = Number(rows[0]?.recent) || 0;
    prior = Number(rows[0]?.prior) || 0;
    if (recent >= SPIKE_MIN && recent > prior * SPIKE_MULTIPLIER) {
      await sendAlert("error", "Error spike detected", undefined, {
        fields: { "Last hour": recent, "Previous hour": prior },
      });
      fired.push("error_spike");
    }
  } catch {
    /* error_events may not exist yet — non-fatal */
  }

  // 3. Migrations recorded
  try {
    const rows = await sql`SELECT COUNT(*)::int AS count FROM drizzle.__drizzle_migrations`;
    if ((Number(rows[0]?.count) || 0) === 0) {
      await sendAlert("warn", "No migrations recorded", "drizzle.__drizzle_migrations is empty", { silent: true });
      fired.push("no_migrations");
    }
  } catch {
    /* ignore */
  }

  // 4. Integration env presence
  const missing: string[] = [];
  if (!(process.env.LITELLM_BASE_URL && process.env.LITELLM_API_KEY)) missing.push("AI Gateway");
  if (!(process.env.R2_ACCOUNT_ID && process.env.R2_ACCESS_KEY_ID && process.env.R2_BUCKET_NAME)) missing.push("R2 Storage");
  if (!process.env.RESEND_API_KEY) missing.push("Email");
  if (missing.length) {
    await sendAlert("warn", "Integration config missing", missing.join(", "), { silent: true });
    fired.push("config_missing");
  }

  return NextResponse.json({ ok: true, dbOk: true, errors: { recent, prior }, fired });
}
