// biome-ignore-all lint/suspicious/noExplicitAny: Allow any
import assert from "node:assert";
import { afterEach, beforeEach, describe, it, mock } from "node:test";
import fastifyMultipart from "@fastify/multipart";
import { cleanupTestDir, createTempTestDir, createTestFastifyInstance, createTestFileStructure, mockLogger, } from "../test-utils/setup.js";
import { createApiRoutes } from "./api.js";
describe("API Routes", () => {
    let app;
    let testDir;
    let sseClients;
    let originalFetch;
    let fetchMock;
    beforeEach(async () => {
        testDir = await createTempTestDir("api-test-");
        await createTestFileStructure(testDir);
        sseClients = new Set();
        app = await createTestFastifyInstance();
        await app.register(fastifyMultipart);
        await app.register(createApiRoutes, {
            sourceDirectory: testDir,
            logger: mockLogger,
            sseClients,
            deploymentUrl: "http://localhost:9000",
        });
        await app.ready();
        // Mock global fetch for CDN tests
        originalFetch = global.fetch;
        fetchMock = mock.fn(global.fetch);
        global.fetch = fetchMock;
    });
    afterEach(async () => {
        await app.close();
        await cleanupTestDir(testDir);
        // Restore original fetch
        global.fetch = originalFetch;
        fetchMock.mock.resetCalls();
    });
    describe("GET /ping", () => {
        it("should return 200 for health check", async () => {
            const response = await app.inject({
                method: "GET",
                url: "/ping",
            });
            assert.strictEqual(response.statusCode, 200);
        });
    });
    describe("GET /v1/deployments/local", () => {
        it("should return deployment info with URL", async () => {
            const response = await app.inject({
                method: "GET",
                url: "/v1/deployments/local",
            });
            assert.strictEqual(response.statusCode, 200);
            const body = JSON.parse(response.body);
            assert.ok(body.deploymentVersion);
            assert.ok(Array.isArray(body.deploymentVersion.stages));
            assert.strictEqual(body.deploymentVersion.stages.length, 1);
            assert.strictEqual(body.deploymentVersion.stages[0].stage, "api");
            assert.strictEqual(body.deploymentVersion.stages[0].url, "http://localhost:9000");
        });
    });
    describe.skip("GET /changes (SSE)", () => {
        // Note: SSE endpoint testing is skipped because it hijacks the connection
        // and inject() doesn't handle this properly. The endpoint would need
        // integration testing with a real HTTP connection.
        it("should establish SSE connection", async () => {
            // Skipped - SSE hijacks connection and causes hanging with inject()
        });
    });
    describe("GET /schemas/*", () => {
        it("should proxy schema requests to CDN", async () => {
            const mockSchemaContent = JSON.stringify({
                type: "object",
                properties: {},
            });
            fetchMock.mock.mockImplementation(async (url) => {
                const urlString = typeof url === "string" ? url : url.toString();
                if (urlString.includes("cdn.zuplo.com")) {
                    return new Response(mockSchemaContent, {
                        status: 200,
                        headers: {
                            "content-type": "application/json",
                        },
                    });
                }
                return new Response("Not Found", { status: 404 });
            });
            const response = await app.inject({
                method: "GET",
                url: "/schemas/openapi-v3.1-zuplo.json",
            });
            assert.strictEqual(response.statusCode, 200);
            assert.strictEqual(response.body, mockSchemaContent);
            // Verify CDN was called
            assert.strictEqual(fetchMock.mock.calls.length, 1);
            const calledUrl = fetchMock.mock.calls[0].arguments[0];
            const urlString = typeof calledUrl === "string" ? calledUrl : calledUrl.toString();
            assert.ok(urlString.includes("https://cdn.zuplo.com/schemas/openapi-v3.1-zuplo.json"));
        });
        it("should preserve content-type from CDN", async () => {
            fetchMock.mock.mockImplementation(async () => {
                return new Response("schema content", {
                    status: 200,
                    headers: {
                        "content-type": "application/schema+json",
                    },
                });
            });
            const response = await app.inject({
                method: "GET",
                url: "/schemas/test-schema.json",
            });
            assert.strictEqual(response.statusCode, 200);
            // Fastify may add charset to content-type
            const contentType = response.headers["content-type"];
            assert.ok(contentType &&
                typeof contentType === "string" &&
                contentType.includes("application/schema+json"));
        });
        it("should return 404 when CDN returns 404", async () => {
            fetchMock.mock.mockImplementation(async () => {
                return new Response("Not Found", { status: 404 });
            });
            const response = await app.inject({
                method: "GET",
                url: "/schemas/nonexistent.json",
            });
            assert.strictEqual(response.statusCode, 404);
        });
        it("should handle CDN errors", async () => {
            fetchMock.mock.mockImplementation(async () => {
                return new Response("Server Error", { status: 500 });
            });
            const response = await app.inject({
                method: "GET",
                url: "/schemas/broken.json",
            });
            assert.strictEqual(response.statusCode, 404);
        });
    });
    describe("Nested route registration", () => {
        it("should register filesystem routes at /v1/deployments/local/fs", async () => {
            const response = await app.inject({
                method: "GET",
                url: "/v1/deployments/local/fs/dir?path=/",
            });
            assert.strictEqual(response.statusCode, 200);
            const body = JSON.parse(response.body);
            assert.ok(Array.isArray(body.result));
        });
        it("should register editor routes at /v1/editor", async () => {
            const response = await app.inject({
                method: "GET",
                url: "/v1/editor/list",
            });
            assert.strictEqual(response.statusCode, 200);
            const body = JSON.parse(response.body);
            assert.ok(Array.isArray(body.editors));
        });
        it("should register test routes at /v1/test", async () => {
            // Mock fetch for test route
            fetchMock.mock.mockImplementation(async () => {
                return new Response("ok", { status: 200 });
            });
            const response = await app.inject({
                method: "POST",
                url: "/v1/test/",
                payload: {
                    method: "GET",
                    path: "/hello",
                },
            });
            assert.strictEqual(response.statusCode, 200);
        });
    });
});
//# sourceMappingURL=api.spec.js.map