import { db } from "@/db/client";
import { agentHeartbeats } from "@/db/schema";
import { timingSafeEqual } from "node:crypto";

export const dynamic = "force-dynamic";

// Machine-to-machine endpoint. Remote hosts (silenus, edda) post here on a
// timer so Ampelos knows whether their storage is currently reachable;
// see src/lib/agents.ts for how staleness is interpreted.

function tokenMatches(provided: string, expected: string) {
  const a = Buffer.from(provided);
  const b = Buffer.from(expected);
  // timingSafeEqual throws on length mismatch, so guard first.
  return a.length === b.length && timingSafeEqual(a, b);
}

function authorize(request: Request) {
  const expected = process.env.AMPELOS_AGENT_TOKEN;
  if (!expected) return { ok: false, status: 503, error: "AMPELOS_AGENT_TOKEN is not configured" };

  const header = request.headers.get("authorization") ?? "";
  const provided = header.startsWith("Bearer ") ? header.slice(7) : "";
  if (!provided || !tokenMatches(provided, expected)) {
    return { ok: false, status: 401, error: "unauthorized" };
  }

  return { ok: true as const };
}

export async function POST(request: Request) {
  const auth = authorize(request);
  if (!auth.ok) return Response.json({ error: auth.error }, { status: auth.status });

  let body: unknown;
  try {
    body = await request.json();
  } catch {
    return Response.json({ error: "invalid JSON body" }, { status: 400 });
  }

  const payload = body as Record<string, unknown> | null;
  const agent = typeof payload?.agent === "string" ? payload.agent.trim() : "";
  if (!agent) return Response.json({ error: "agent is required" }, { status: 400 });

  const hostname = typeof payload?.hostname === "string" ? payload.hostname : null;
  const version = typeof payload?.version === "string" ? payload.version : null;
  const details = payload?.details ?? null;

  const now = new Date();
  await db
    .insert(agentHeartbeats)
    .values({ agent, hostname, version, details, firstSeenAt: now, lastSeenAt: now })
    .onConflictDoUpdate({
      target: agentHeartbeats.agent,
      // firstSeenAt is deliberately not touched — it records the first contact.
      set: { hostname, version, details, lastSeenAt: now },
    });

  return Response.json({ ok: true, agent, receivedAt: now.toISOString() });
}

// Lets an agent verify connectivity and credentials without recording a beat.
export async function GET(request: Request) {
  const auth = authorize(request);
  if (!auth.ok) return Response.json({ error: auth.error }, { status: auth.status });
  return Response.json({ ok: true });
}
