import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import * as lark from "@larksuiteoapi/node-sdk";
import { afterEach, describe, expect, it } from "vitest";

const openServers: ReturnType<typeof createServer>[] = [];

describe("real Lark SDK HTTP transport", () => {
  afterEach(async () => {
    await Promise.all(openServers.splice(0).map(async (server) => {
      server.closeAllConnections();
      await new Promise<void>((resolve, reject) => {
        server.close((error) => error === undefined ? resolve() : reject(error));
      });
    }));
  });

  it("uses overridden Axios for token, authenticated success, and HTTP error paths", async () => {
    const requests: Array<{
      readonly method: string | undefined;
      readonly url: string | undefined;
      readonly authorization: string | undefined;
      readonly body: string;
    }> = [];
    const server = createServer(async (request, response) => {
      const body = await readBody(request);
      requests.push({
        method: request.method,
        url: request.url,
        authorization: request.headers.authorization,
        body,
      });
      routeSmokeRequest(request, response, body);
    });
    openServers.push(server);
    await new Promise<void>((resolve, reject) => {
      server.once("error", reject);
      server.listen(0, "127.0.0.1", resolve);
    });
    const address = server.address();
    if (address === null || typeof address === "string") throw new Error("local HTTP server has no TCP address");
    const domain = `http://127.0.0.1:${address.port}`;
    const client = new lark.Client({
      appId: "cli_transport_smoke",
      appSecret: "transport-smoke-secret",
      domain,
      loggerLevel: lark.LoggerLevel.error,
    });

    await expect(client.request<{ readonly code: number; readonly data: { readonly ok: boolean } }>({
      method: "GET",
      url: "/open-apis/smoke/success",
      params: { probe: "axios-override" },
    })).resolves.toEqual({ code: 0, data: { ok: true } });

    await expect(client.request({
      method: "GET",
      url: "/open-apis/smoke/failure",
    })).rejects.toMatchObject({
      response: {
        status: 429,
        data: { code: 999_429, msg: "forced smoke failure" },
      },
    });

    expect(requests).toHaveLength(3);
    expect(requests[0]).toMatchObject({
      method: "POST",
      url: "/open-apis/auth/v3/tenant_access_token/internal",
      authorization: undefined,
    });
    expect(JSON.parse(requests[0]!.body)).toEqual({
      app_id: "cli_transport_smoke",
      app_secret: "transport-smoke-secret",
    });
    expect(requests[1]).toMatchObject({
      method: "GET",
      url: "/open-apis/smoke/success?probe=axios-override",
      authorization: "Bearer tenant-transport-smoke",
    });
    expect(requests[2]).toMatchObject({
      method: "GET",
      url: "/open-apis/smoke/failure",
      authorization: "Bearer tenant-transport-smoke",
    });
  });
});

async function readBody(request: IncomingMessage): Promise<string> {
  const chunks: Buffer[] = [];
  for await (const chunk of request) {
    chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
  }
  return Buffer.concat(chunks).toString("utf8");
}

function routeSmokeRequest(request: IncomingMessage, response: ServerResponse, body: string): void {
  if (request.method === "POST" && request.url === "/open-apis/auth/v3/tenant_access_token/internal") {
    const credential = JSON.parse(body) as { app_id?: unknown; app_secret?: unknown };
    if (credential.app_id !== "cli_transport_smoke" || credential.app_secret !== "transport-smoke-secret") {
      sendJson(response, 401, { code: 401, msg: "bad smoke credential" });
      return;
    }
    sendJson(response, 200, {
      code: 0,
      msg: "ok",
      tenant_access_token: "tenant-transport-smoke",
      expire: 3_600,
    });
    return;
  }
  if (request.method === "GET" && request.url === "/open-apis/smoke/success?probe=axios-override") {
    sendJson(response, 200, { code: 0, data: { ok: true } });
    return;
  }
  if (request.method === "GET" && request.url === "/open-apis/smoke/failure") {
    sendJson(response, 429, { code: 999_429, msg: "forced smoke failure" });
    return;
  }
  sendJson(response, 404, { code: 404, msg: "unknown smoke route" });
}

function sendJson(response: ServerResponse, statusCode: number, body: unknown): void {
  response.writeHead(statusCode, { "content-type": "application/json" });
  response.end(JSON.stringify(body));
}
