import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import { resolveApiKeyUser } from "@/lib/api-auth";

/**
 * POST /api/devices/heartbeat
 *
 * Called by CLI every 30 seconds to keep device marked as online.
 * Updates last_seen, status, latency, and optionally models.
 */
export async function POST(req: NextRequest) {
  const user = await resolveApiKeyUser(req);
  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    const {
      device_id,
      name,
      tunnel_url,
      models,
      latency_ms,
      status,
      // Enhanced heartbeat fields (Phase 3)
      vram_usage_mb,
      active_model,
      requests_served,
      uptime_seconds,
      savings_usd,
    } = body;

    // Find device by ID or name
    const where = device_id
      ? { id: device_id, userId: user.id }
      : name
        ? { userId_name: { userId: user.id, name } }
        : null;

    if (!where) {
      return NextResponse.json(
        { error: "device_id or name is required" },
        { status: 400 },
      );
    }

    const updateData: Record<string, unknown> = {
      lastSeen: new Date(),
      status: status || "online",
    };

    if (tunnel_url) updateData.tunnelUrl = tunnel_url;
    if (models) updateData.models = JSON.stringify(models);
    if (latency_ms !== undefined) updateData.latencyMs = Math.round(latency_ms);

    // Enhanced heartbeat fields
    if (vram_usage_mb !== undefined && typeof vram_usage_mb === "number") {
      updateData.vramUsageMb = Math.round(vram_usage_mb);
    }
    if (active_model !== undefined) {
      updateData.activeModel = typeof active_model === "string" ? active_model : null;
    }
    if (requests_served !== undefined && typeof requests_served === "number") {
      updateData.requestsServed = Math.max(0, Math.round(requests_served));
    }
    if (uptime_seconds !== undefined && typeof uptime_seconds === "number") {
      updateData.uptimeSeconds = Math.max(0, Math.round(uptime_seconds));
    }
    if (savings_usd !== undefined && typeof savings_usd === "number") {
      updateData.savingsUsd = Math.max(0, savings_usd);
    }

    // Use upsert when looking up by name — auto-creates device if registration
    // was skipped (e.g. tunnel setup failed but auth succeeded). Devices are
    // still valuable for dashboard status tracking without a tunnel.
    const device = device_id
      ? await db.device.update({ where, data: updateData })
      : await db.device.upsert({
          where: where as { userId_name: { userId: string; name: string } },
          update: updateData,
          create: {
            userId: user.id,
            name: name as string,
            status: (status as string) || "online",
            lastSeen: new Date(),
            tunnelUrl: (tunnel_url as string) || "",
            models: models ? JSON.stringify(models) : "[]",
            hardware: "",
          },
        });

    // Return the user's current plan so the CLI can detect downgrades
    return NextResponse.json({
      id: device.id,
      status: device.status,
      last_seen: device.lastSeen,
      plan: user.plan,
    });
  } catch {
    return NextResponse.json(
      { error: "Heartbeat failed" },
      { status: 500 },
    );
  }
}
