import { describe, expect, it, afterAll } from "bun:test";
import { startGatewayServer } from "../src/index";

function startUpstream() {
  let lastHeaders: Headers | null = null;
  const server = Bun.serve({
    port: 0,
    async fetch(req) {
      lastHeaders = req.headers;
      const url = new URL(req.url);
      if (url.pathname === "/gateway/fetch") {
        const body = await req.json();
        return Response.json({ status: "success", message: "ok", data: { echo: body } });
      }
      return new Response("not found", { status: 404 });
    },
  });
  return { server, getLastHeaders: () => lastHeaders };
}

describe("wss gateway", () => {
  const upstream = startUpstream();
  const gateway = startGatewayServer({ apiBase: `http://localhost:${upstream.server.port}`, port: 0 });
  const baseUrl = `http://localhost:${gateway.port}`;

  afterAll(() => {
    gateway.stop();
    upstream.server.stop();
  });

  it("exposes info and health endpoints", async () => {
    const info = await fetch(`${baseUrl}/wss/info`).then((r) => r.json());
    expect(info.status).toBe("success");
    expect(info.data.api_base).toContain(`:${upstream.server.port}`);

    const health = await fetch(`${baseUrl}/health`).then((r) => r.json());
    expect(health.status).toBe("ok");
  });

  it("proxies websocket messages to upstream gateway", async () => {
    const ws = new WebSocket(`${baseUrl.replace("http", "ws")}/wss/gateway`);

    const openPromise = new Promise<void>((resolve, reject) => {
      const timer = setTimeout(() => reject(new Error("ws open timeout")), 2000);
      ws.addEventListener("open", () => {
        clearTimeout(timer);
        resolve();
      });
    });

    await openPromise;

    const responsePromise = new Promise<any>((resolve, reject) => {
      const timer = setTimeout(() => reject(new Error("ws message timeout")), 3000);
      ws.addEventListener("message", (event) => {
        const parsed = JSON.parse(event.data as string);
        if (parsed.data?.body?.data?.echo) {
          clearTimeout(timer);
          resolve(parsed);
        }
      });
    });

    ws.send(
      JSON.stringify({
        action: "gateway.fetch",
        client_name: "test_client",
        path: "/gateway/fetch",
        body: { resource: "users", limit: 1 },
        request_id: "abc-123",
      }),
    );

    const payload = await responsePromise;
    expect(payload.status).toBe("success");
    expect(payload.request_id).toBe("abc-123");
    expect(payload.data.body.data.echo.resource).toBe("users");

    const headers = upstream.getLastHeaders();
    expect(headers?.get("x-athena-client")).toBe("test_client");

    ws.close();
  });
});
