import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
import type { AddressInfo } from "node:net";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { generatePrivateKey } from "viem/accounts";

import { startProxy, type ProxyHandle } from "./proxy.js";

describe("blockrun-exa proxying", () => {
  let upstream: Server;
  let proxy: ProxyHandle;
  let upstreamUrl = "";
  let receivedPath = "";
  let receivedBody: Record<string, unknown> | null = null;

  beforeAll(async () => {
    upstream = createServer(async (req: IncomingMessage, res: ServerResponse) => {
      receivedPath = req.url ?? "";

      const chunks: Buffer[] = [];
      for await (const chunk of req) {
        chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
      }

      receivedBody = JSON.parse(Buffer.concat(chunks).toString()) as Record<string, unknown>;

      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(
        JSON.stringify({
          results: [
            {
              title: "Result",
              url: "https://example.com/result",
              summary: "A result from upstream.",
            },
          ],
        }),
      );
    });

    await new Promise<void>((resolve) => upstream.listen(0, "127.0.0.1", resolve));
    const addr = upstream.address() as AddressInfo;
    upstreamUrl = `http://127.0.0.1:${addr.port}`;

    proxy = await startProxy({
      wallet: generatePrivateKey(),
      apiBase: upstreamUrl,
      port: 0,
      skipBalanceCheck: true,
    });
  }, 10_000);

  afterAll(async () => {
    await proxy?.close();
    await new Promise<void>((resolve) => upstream.close(() => resolve()));
  });

  it("forwards /v1/exa/search through the paid proxy path", async () => {
    receivedPath = "";
    receivedBody = null;

    const res = await fetch(`${proxy.baseUrl}/v1/exa/search`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        query: "latest ai news",
        numResults: 4,
        includeDomains: ["openai.com"],
      }),
    });

    expect(res.status).toBe(200);
    expect(receivedPath).toBe("/v1/exa/search");
    expect(receivedBody).toEqual({
      query: "latest ai news",
      numResults: 4,
      includeDomains: ["openai.com"],
    });
    await expect(res.json()).resolves.toEqual({
      results: [
        {
          title: "Result",
          url: "https://example.com/result",
          summary: "A result from upstream.",
        },
      ],
    });
  });
});
