import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("../../utils/logger.js", () => ({
    logger: {
        debug: vi.fn(),
        info: vi.fn(),
        warn: vi.fn(),
        error: vi.fn(),
    },
}));
// Mock global fetch
const mockFetch = vi.fn();
vi.stubGlobal("fetch", mockFetch);
import { proxyToOpenCode, setOpenCodeAuth, clearOpenCodeAuth, getOpenCodeAuth, } from "../proxy.js";
describe("OpenCode HTTP Proxy", () => {
    const testAuth = {
        password: "test-password",
        baseUrl: "http://127.0.0.1:4096",
        authHeader: "Basic b3BlbmNvZGU6dGVzdC1wYXNzd29yZA==",
    };
    beforeEach(() => {
        mockFetch.mockReset();
        clearOpenCodeAuth();
    });
    describe("setOpenCodeAuth / getOpenCodeAuth / clearOpenCodeAuth", () => {
        it("should store and retrieve auth credentials", () => {
            expect(getOpenCodeAuth()).toBeNull();
            setOpenCodeAuth(testAuth);
            expect(getOpenCodeAuth()).toEqual(testAuth);
        });
        it("should clear auth credentials", () => {
            setOpenCodeAuth(testAuth);
            clearOpenCodeAuth();
            expect(getOpenCodeAuth()).toBeNull();
        });
    });
    describe("proxyToOpenCode", () => {
        it("should throw OPENCODE_UNREACHABLE when auth is not set", async () => {
            const request = { method: "GET", path: "/global/health" };
            await expect(proxyToOpenCode(request)).rejects.toThrow("OPENCODE_UNREACHABLE");
        });
        it("should forward GET requests with auth header", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers({ "content-type": "application/json" }),
                text: async () => JSON.stringify({ healthy: true, version: "1.0.0" }),
            });
            const request = { method: "GET", path: "/global/health" };
            const response = await proxyToOpenCode(request);
            expect(response.status).toBe(200);
            expect(response.body).toContain("healthy");
            // Verify auth header was included
            const fetchCall = mockFetch.mock.calls[0];
            expect(fetchCall[0]).toBe("http://127.0.0.1:4096/global/health");
            const headers = fetchCall[1].headers;
            expect(headers.Authorization).toBe(testAuth.authHeader);
        });
        it("should forward POST requests with body", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers({ "content-type": "application/json" }),
                text: async () => JSON.stringify({ id: "session-1" }),
            });
            const body = JSON.stringify({ directory: "/tmp/project" });
            const request = { method: "POST", path: "/session", body };
            const response = await proxyToOpenCode(request);
            expect(response.status).toBe(200);
            const fetchCall = mockFetch.mock.calls[0];
            expect(fetchCall[1].method).toBe("POST");
            expect(fetchCall[1].body).toBe(body);
            const headers = fetchCall[1].headers;
            expect(headers["Content-Type"]).toBe("application/json");
        });
        it("should forward query parameters", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers(),
                text: async () => "[]",
            });
            const request = {
                method: "GET",
                path: "/session",
                query: { limit: "10", search: "test" },
            };
            await proxyToOpenCode(request);
            const fetchCall = mockFetch.mock.calls[0];
            const url = new URL(fetchCall[0]);
            expect(url.searchParams.get("limit")).toBe("10");
            expect(url.searchParams.get("search")).toBe("test");
        });
        it("should forward response status and headers", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 404,
                headers: new Headers({
                    "content-type": "application/json",
                    "x-custom": "value",
                }),
                text: async () => JSON.stringify({ error: "not found" }),
            });
            const request = { method: "GET", path: "/session/unknown" };
            const response = await proxyToOpenCode(request);
            expect(response.status).toBe(404);
            expect(response.headers["content-type"]).toBe("application/json");
            expect(response.headers["x-custom"]).toBe("value");
        });
        it("should handle empty response body", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 204,
                headers: new Headers(),
                text: async () => "",
            });
            const request = { method: "DELETE", path: "/session/123" };
            const response = await proxyToOpenCode(request);
            expect(response.status).toBe(204);
            expect(response.body).toBeUndefined();
        });
        it("should throw TIMEOUT on request timeout", async () => {
            setOpenCodeAuth(testAuth);
            const timeoutError = new DOMException("The operation was aborted.", "TimeoutError");
            mockFetch.mockRejectedValueOnce(timeoutError);
            const request = { method: "GET", path: "/session" };
            await expect(proxyToOpenCode(request, 100)).rejects.toThrow("TIMEOUT");
        });
        it("should throw OPENCODE_UNREACHABLE on connection refused", async () => {
            setOpenCodeAuth(testAuth);
            const connError = new TypeError("fetch failed: ECONNREFUSED");
            mockFetch.mockRejectedValueOnce(connError);
            const request = { method: "GET", path: "/session" };
            await expect(proxyToOpenCode(request)).rejects.toThrow("OPENCODE_UNREACHABLE");
        });
        it("should not send body for GET requests", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers(),
                text: async () => "{}",
            });
            const request = { method: "GET", path: "/provider" };
            await proxyToOpenCode(request);
            const fetchCall = mockFetch.mock.calls[0];
            expect(fetchCall[1].body).toBeUndefined();
        });
        it("should preserve custom headers from request", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers(),
                text: async () => "{}",
            });
            const request = {
                method: "GET",
                path: "/session",
                headers: { "X-Request-Id": "abc-123" },
            };
            await proxyToOpenCode(request);
            const fetchCall = mockFetch.mock.calls[0];
            const headers = fetchCall[1].headers;
            expect(headers["X-Request-Id"]).toBe("abc-123");
            expect(headers.Authorization).toBe(testAuth.authHeader);
        });
        it("should use AbortSignal.timeout for request timeout", async () => {
            setOpenCodeAuth(testAuth);
            mockFetch.mockResolvedValueOnce({
                status: 200,
                headers: new Headers(),
                text: async () => "{}",
            });
            const request = { method: "GET", path: "/session" };
            await proxyToOpenCode(request, 5000);
            const fetchCall = mockFetch.mock.calls[0];
            expect(fetchCall[1].signal).toBeDefined();
        });
    });
});
//# sourceMappingURL=proxy.test.js.map