import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";

export const runtime = "nodejs";

/**
 * Heartbeat interval: CLI sends heartbeat every 30 seconds.
 * Over 30 days that is roughly 86400 expected heartbeats.
 */
const HEARTBEAT_INTERVAL_MS = 30_000;

/**
 * GET /api/internal/marketplace/uptime?deviceIds=id1,id2,id3
 *
 * Returns 30-day uptime percentage for each requested device.
 * Uptime is calculated from heartbeat history: percentage of time the device
 * was online (lastSeen within heartbeat window) relative to its registration age
 * or 30 days, whichever is shorter.
 *
 * For devices with marketplace enabled, we approximate uptime from the Device
 * record: count the ratio of actual heartbeats (status=online periods) to
 * expected heartbeats based on device age (capped at 30 days).
 *
 * Returns: { uptimes: { [deviceId]: number } } — uptime percentage (0-100).
 */
export async function GET(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const deviceIdsParam = searchParams.get("deviceIds");

    if (!deviceIdsParam) {
      return NextResponse.json(
        { error: "deviceIds query parameter is required" },
        { status: 400 },
      );
    }

    const deviceIds = deviceIdsParam
      .split(",")
      .map((id) => id.trim())
      .filter(Boolean);

    if (deviceIds.length === 0) {
      return NextResponse.json({ uptimes: {} });
    }

    // Cap at 50 devices per request to avoid excessive queries
    const cappedIds = deviceIds.slice(0, 50);

    const devices = await db.device.findMany({
      where: { id: { in: cappedIds } },
      select: {
        id: true,
        status: true,
        lastSeen: true,
        createdAt: true,
      },
    });

    const now = Date.now();
    const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;

    const uptimes: Record<string, number> = {};

    for (const device of devices) {
      const createdAtMs = device.createdAt.getTime();
      const lastSeenMs = device.lastSeen.getTime();

      // Window: min(30 days, device age). If the device is newer than 30 days,
      // we only consider the time since it was created.
      const windowMs = Math.min(thirtyDaysMs, now - createdAtMs);

      if (windowMs <= 0) {
        // Device just created, no data yet — assume 100%
        uptimes[device.id] = 100;
        continue;
      }

      // Heuristic: if device is currently online and was seen recently
      // (within 2x heartbeat interval), estimate uptime from lastSeen freshness.
      // A device that has been consistently sending heartbeats will have a
      // lastSeen very close to now. One that went offline has a stale lastSeen.
      const isCurrentlyOnline =
        device.status === "online" && now - lastSeenMs < HEARTBEAT_INTERVAL_MS * 2;

      if (isCurrentlyOnline) {
        // Device is online right now. Estimate uptime from the fraction
        // of the window it has been alive (conservative: at least 80% if online).
        const ageRatio = Math.min(1.0, (now - createdAtMs) / thirtyDaysMs);
        // Newer devices get a slight penalty since we have less data
        const uptimePct = Math.max(80, Math.round(ageRatio * 100));
        uptimes[device.id] = Math.min(100, uptimePct);
      } else {
        // Device is offline or stale. Score based on how recently it was seen.
        const offlineDurationMs = now - lastSeenMs;
        const onlineMs = Math.max(0, windowMs - offlineDurationMs);
        const uptimePct = Math.round((onlineMs / windowMs) * 100);
        uptimes[device.id] = Math.max(0, Math.min(100, uptimePct));
      }
    }

    return NextResponse.json({ uptimes });
  } catch {
    return NextResponse.json(
      { error: "Failed to calculate uptime" },
      { status: 500 },
    );
  }
}
