import { describe, it, expect, vi } from "vitest";
import { Hono } from "hono";
import { createHealthRoutes, createDetailedHealthRoutes } from "./health.js";
import type { WsBridge } from "./ws-bridge.js";

function buildApp(overrides: { version?: string; wsBridge?: Record<string, unknown> } = {}) {
  const wsBridge = {
    getAllSessions: vi.fn(() => []),
    ...overrides.wsBridge,
  } as unknown as WsBridge;

  const app = new Hono();
  app.route("", createHealthRoutes({ version: overrides.version ?? "1.2.3", wsBridge }));
  return { app, wsBridge };
}

function buildDetailedApp(overrides: { version?: string; wsBridge?: Record<string, unknown> } = {}) {
  const wsBridge = {
    getAllSessions: vi.fn(() => []),
    ...overrides.wsBridge,
  } as unknown as WsBridge;

  const app = new Hono();
  app.route("/api/health", createDetailedHealthRoutes({ version: overrides.version ?? "1.2.3", wsBridge }));
  return { app, wsBridge };
}

describe("GET /health", () => {
  it("returns 200 with status, version, and uptime", async () => {
    const { app } = buildApp({ version: "0.59.0" });
    const res = await app.request("/health");
    expect(res.status).toBe(200);

    const body = await res.json();
    expect(body.status).toBe("ok");
    expect(body.version).toBe("0.59.0");
    expect(typeof body.uptime).toBe("number");
    expect(body.uptime).toBeGreaterThanOrEqual(0);
  });

  it("does not require authentication", async () => {
    const { app } = buildApp();
    const res = await app.request("/health");
    // No auth header — should still succeed
    expect(res.status).toBe(200);
  });
});

describe("GET /ready", () => {
  it("returns 200 with only status and version (no activeSessions)", async () => {
    const { app } = buildApp({ version: "0.59.0" });

    const res = await app.request("/ready");
    expect(res.status).toBe(200);

    const body = await res.json();
    expect(body.status).toBe("ok");
    expect(body.version).toBe("0.59.0");
    expect(body).not.toHaveProperty("activeSessions");
    expect(body).not.toHaveProperty("uptime");
  });

  it("does not require authentication", async () => {
    const { app } = buildApp();
    const res = await app.request("/ready");
    expect(res.status).toBe(200);
  });
});

describe("GET /api/health/detailed", () => {
  it("returns 200 with status, version, uptime, and activeSessions", async () => {
    const sessions = [{ id: "a" }, { id: "b" }, { id: "c" }] as unknown[];
    const { app } = buildDetailedApp({
      version: "0.59.0",
      wsBridge: { getAllSessions: vi.fn(() => sessions) },
    });

    const res = await app.request("/api/health/detailed");
    expect(res.status).toBe(200);

    const body = await res.json();
    expect(body.status).toBe("ok");
    expect(body.version).toBe("0.59.0");
    expect(typeof body.uptime).toBe("number");
    expect(body.activeSessions).toBe(3);
  });

  it("returns activeSessions 0 when no sessions exist", async () => {
    const { app } = buildDetailedApp();
    const res = await app.request("/api/health/detailed");
    expect(res.status).toBe(200);

    const body = await res.json();
    expect(body.activeSessions).toBe(0);
  });

  it("returns 503 when session store is unavailable", async () => {
    const { app } = buildDetailedApp({
      wsBridge: {
        getAllSessions: vi.fn(() => {
          throw new Error("store crashed");
        }),
      },
    });

    const res = await app.request("/api/health/detailed");
    expect(res.status).toBe(503);

    const body = await res.json();
    expect(body.status).toBe("error");
    expect(body.message).toBe("Session store unavailable");
  });
});
