import { afterEach, describe, expect, test } from "bun:test";
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { createOpenApi, generateApiArtifacts, inspectApi } from "../src/api-command.ts";

const roots: string[] = [];
afterEach(async () =>
  Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))),
);
async function fixture() {
  const root = join(tmpdir(), `wrnexus-api-${crypto.randomUUID()}`);
  roots.push(root);
  await mkdir(join(root, "app", "api", "users"), { recursive: true });
  await writeFile(
    join(root, "app", "api", "users", "[id].ts"),
    "export async function GET(){}\nexport const PATCH = () => {};\n",
  );
  return root;
}

describe("API and SDK generation", () => {
  test("derives methods, paths and OpenAPI operations from file routes", async () => {
    const operations = inspectApi(await fixture());
    expect(operations.map((operation) => `${operation.method} ${operation.path}`)).toEqual([
      "GET /api/users/{id}",
      "PATCH /api/users/{id}",
    ]);
    expect(createOpenApi(operations).openapi).toBe("3.1.0");
  });
  test("emits docs, Postman, examples and all requested SDK languages", async () => {
    const root = await fixture();
    const result = generateApiArtifacts(root, ["typescript", "javascript", "java", "go", "python"]);
    expect(result.files).toHaveLength(9);
    expect(
      JSON.parse(await readFile(join(root, "generated/api/openapi.json"), "utf8")).paths[
        "/api/users/{id}"
      ].get.operationId,
    ).toBe("getUsersId");
    expect(await readFile(join(root, "generated/api/sdk/python/wrnexus-api.py"), "utf8")).toContain(
      "class WrnexusApi",
    );
  });
  test("extracts webhook prose and schemas into OpenAPI 3.1 webhooks", async () => {
    const root = await fixture();
    await mkdir(join(root, "app", "api", "webhooks"), { recursive: true });
    await writeFile(
      join(root, "app", "api", "webhooks", "payment.ts"),
      `
      export const webhook = defineWebhook({
        event: "payment.completed",
        summary: "Payment completed",
        description: "Sent after settlement.",
        payloadSchema: "#/components/schemas/Payment",
        signatureHeader: "x-payment-signature"
      });
      export const POST = () => new Response("ok");
    `,
    );
    const spec = createOpenApi(inspectApi(root)) as any;
    expect(spec.webhooks["payment.completed"].post.description).toBe("Sent after settlement.");
    expect(
      spec.webhooks["payment.completed"].post.requestBody.content["application/json"].schema.$ref,
    ).toBe("#/components/schemas/Payment");
    expect(spec.webhooks["payment.completed"].post.parameters[0].name).toBe("x-payment-signature");
  });
});
