import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("@/lib/db", () => ({
  db: {
    device: {
      findMany: vi.fn(),
    },
  },
}));

import { db } from "@/lib/db";

describe("GET /api/internal/marketplace/uptime", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.resetModules();
  });

  it("should return 400 when deviceIds is missing", async () => {
    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(400);
    const body = await response.json();
    expect(body.error).toContain("deviceIds");
  });

  it("should return empty uptimes for empty deviceIds", async () => {
    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(400);
  });

  it("should return uptime for online device", async () => {
    const now = new Date();
    const tenDaysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000);

    vi.mocked(db.device.findMany).mockResolvedValue([
      {
        id: "d1",
        status: "online",
        lastSeen: now,
        createdAt: tenDaysAgo,
        userId: "u1",
        name: "dev1",
        tunnelUrl: "https://t.example.com",
        models: "[]",
        hardware: "",
        latencyMs: 50,
        updatedAt: now,
        marketplaceEnabled: true,
        marketplacePriceCents: 10,
        vramUsageMb: null,
        activeModel: null,
        requestsServed: 0,
        uptimeSeconds: 0,
        savingsUsd: 0,
      },
    ]);

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=d1",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(200);
    const body = await response.json();
    expect(body.uptimes).toBeDefined();
    expect(body.uptimes.d1).toBeGreaterThanOrEqual(80);
    expect(body.uptimes.d1).toBeLessThanOrEqual(100);
  });

  it("should return low uptime for offline device with stale lastSeen", async () => {
    const now = new Date();
    const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
    const twentyDaysAgo = new Date(now.getTime() - 20 * 24 * 60 * 60 * 1000);

    vi.mocked(db.device.findMany).mockResolvedValue([
      {
        id: "d2",
        status: "offline",
        lastSeen: twentyDaysAgo,
        createdAt: thirtyDaysAgo,
        userId: "u1",
        name: "dev2",
        tunnelUrl: "https://t.example.com",
        models: "[]",
        hardware: "",
        latencyMs: null,
        updatedAt: now,
        marketplaceEnabled: true,
        marketplacePriceCents: 10,
        vramUsageMb: null,
        activeModel: null,
        requestsServed: 0,
        uptimeSeconds: 0,
        savingsUsd: 0,
      },
    ]);

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=d2",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(200);
    const body = await response.json();
    expect(body.uptimes.d2).toBeLessThan(50);
  });

  it("should return high uptime for just-created online device", async () => {
    const now = new Date();

    vi.mocked(db.device.findMany).mockResolvedValue([
      {
        id: "d3",
        status: "online",
        lastSeen: now,
        createdAt: now,
        userId: "u1",
        name: "dev3",
        tunnelUrl: "https://t.example.com",
        models: "[]",
        hardware: "",
        latencyMs: 30,
        updatedAt: now,
        marketplaceEnabled: true,
        marketplacePriceCents: 10,
        vramUsageMb: null,
        activeModel: null,
        requestsServed: 0,
        uptimeSeconds: 0,
        savingsUsd: 0,
      },
    ]);

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=d3",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(200);
    const body = await response.json();
    // Just-created device that is online gets at least 80% (floor for online devices)
    expect(body.uptimes.d3).toBeGreaterThanOrEqual(80);
    expect(body.uptimes.d3).toBeLessThanOrEqual(100);
  });

  it("should handle multiple device IDs", async () => {
    const now = new Date();
    const tenDaysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000);

    vi.mocked(db.device.findMany).mockResolvedValue([
      {
        id: "d1",
        status: "online",
        lastSeen: now,
        createdAt: tenDaysAgo,
        userId: "u1",
        name: "dev1",
        tunnelUrl: "https://t.example.com",
        models: "[]",
        hardware: "",
        latencyMs: 30,
        updatedAt: now,
        marketplaceEnabled: true,
        marketplacePriceCents: 10,
        vramUsageMb: null,
        activeModel: null,
        requestsServed: 0,
        uptimeSeconds: 0,
        savingsUsd: 0,
      },
      {
        id: "d2",
        status: "offline",
        lastSeen: tenDaysAgo,
        createdAt: tenDaysAgo,
        userId: "u2",
        name: "dev2",
        tunnelUrl: "https://t2.example.com",
        models: "[]",
        hardware: "",
        latencyMs: null,
        updatedAt: now,
        marketplaceEnabled: true,
        marketplacePriceCents: 15,
        vramUsageMb: null,
        activeModel: null,
        requestsServed: 0,
        uptimeSeconds: 0,
        savingsUsd: 0,
      },
    ]);

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=d1,d2",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(200);
    const body = await response.json();
    expect(Object.keys(body.uptimes)).toHaveLength(2);
    expect(body.uptimes.d1).toBeGreaterThan(body.uptimes.d2);
  });

  it("should return empty map for unknown device IDs", async () => {
    vi.mocked(db.device.findMany).mockResolvedValue([]);

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=unknown1,unknown2",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(200);
    const body = await response.json();
    expect(body.uptimes).toEqual({});
  });

  it("should handle db errors gracefully", async () => {
    vi.mocked(db.device.findMany).mockRejectedValue(new Error("DB failure"));

    const { GET } = await import(
      "@/app/api/internal/marketplace/uptime/route"
    );
    const request = new Request(
      "http://localhost/api/internal/marketplace/uptime?deviceIds=d1",
    );
    const response = await GET(request as never);
    expect(response.status).toBe(500);
  });
});
