import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { EventEmitter } from "node:events";
// Mock env
vi.mock("../../env.js", () => ({
    getEnv: () => ({ gatewayUrl: "wss://pocketcoder-gateway.fly.dev" }),
}));
// Mock crypto.randomUUID for deterministic request IDs
vi.mock("node:crypto", async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        randomUUID: () => "test-uuid-1234",
    };
});
// Create a mock WebSocket that extends EventEmitter
class MockWebSocket extends EventEmitter {
    static OPEN = 1;
    readyState = MockWebSocket.OPEN;
    send = vi.fn();
    close = vi.fn();
}
let mockWsInstance;
vi.mock("ws", () => {
    return {
        default: class {
            constructor() {
                mockWsInstance = new MockWebSocket();
                return mockWsInstance;
            }
        },
    };
});
import { exchangeCodeViaGateway, refreshTokenViaGateway } from "../gateway-auth.js";
describe("gateway-auth", () => {
    beforeEach(() => {
        vi.clearAllMocks();
        vi.useFakeTimers();
    });
    afterEach(() => {
        vi.useRealTimers();
    });
    describe("exchangeCodeViaGateway", () => {
        it("should send auth_exchange message with code", async () => {
            const promise = exchangeCodeViaGateway("test-oauth-code");
            // Simulate WebSocket open
            mockWsInstance.emit("open");
            expect(mockWsInstance.send).toHaveBeenCalledWith(JSON.stringify({
                type: "auth_exchange",
                requestId: "auth_test-uuid-1234",
                payload: { code: "test-oauth-code" },
            }));
            // Simulate response
            mockWsInstance.emit("message", JSON.stringify({
                type: "auth_exchange_response",
                requestId: "auth_test-uuid-1234",
                payload: {
                    access_token: "at-123",
                    refresh_token: "rt-456",
                    expires_at: 1707666000,
                    user: {
                        id: "user-789",
                        email: "user@example.com",
                        github_username: "testuser",
                    },
                },
            }));
            const result = await promise;
            expect(result.access_token).toBe("at-123");
            expect(result.refresh_token).toBe("rt-456");
            expect(result.expires_at).toBe(1707666000);
            expect(result.user.id).toBe("user-789");
            expect(result.user.github_username).toBe("testuser");
        });
        it("should parse auth_exchange_response tokens", async () => {
            const promise = exchangeCodeViaGateway("code-xyz");
            mockWsInstance.emit("open");
            mockWsInstance.emit("message", JSON.stringify({
                type: "auth_exchange_response",
                requestId: "auth_test-uuid-1234",
                payload: {
                    access_token: "eyJ-access",
                    refresh_token: "eyJ-refresh",
                    expires_at: 1707752400,
                    user: {
                        id: "uid-abc",
                        email: "dev@example.com",
                        github_username: "devuser",
                    },
                },
            }));
            const result = await promise;
            expect(result).toEqual({
                access_token: "eyJ-access",
                refresh_token: "eyJ-refresh",
                expires_at: 1707752400,
                user: {
                    id: "uid-abc",
                    email: "dev@example.com",
                    github_username: "devuser",
                },
            });
        });
        it("should handle error response", async () => {
            const promise = exchangeCodeViaGateway("expired-code");
            mockWsInstance.emit("open");
            mockWsInstance.emit("message", JSON.stringify({
                type: "auth_exchange_response",
                requestId: "auth_test-uuid-1234",
                error: {
                    code: "INVALID_CODE",
                    message: "OAuth code is invalid or expired",
                },
            }));
            await expect(promise).rejects.toThrow("Auth exchange failed: OAuth code is invalid or expired");
        });
        it("should timeout if no response", async () => {
            const promise = exchangeCodeViaGateway("code-timeout");
            mockWsInstance.emit("open");
            // Advance past the 30s timeout
            vi.advanceTimersByTime(30_001);
            await expect(promise).rejects.toThrow("Auth request timed out after 30000ms");
            expect(mockWsInstance.close).toHaveBeenCalled();
        });
        it("should handle WebSocket error", async () => {
            const promise = exchangeCodeViaGateway("code-error");
            mockWsInstance.emit("error", new Error("Connection refused"));
            await expect(promise).rejects.toThrow("WebSocket error during auth: Connection refused");
        });
        it("should handle unexpected WebSocket close", async () => {
            const promise = exchangeCodeViaGateway("code-close");
            mockWsInstance.emit("open");
            mockWsInstance.emit("close", 1006);
            await expect(promise).rejects.toThrow("WebSocket closed unexpectedly (code: 1006)");
        });
        it("should ignore messages with wrong requestId", async () => {
            const promise = exchangeCodeViaGateway("my-code");
            mockWsInstance.emit("open");
            // Send a response with wrong requestId - should be ignored
            mockWsInstance.emit("message", JSON.stringify({
                type: "auth_exchange_response",
                requestId: "wrong-request-id",
                payload: {
                    access_token: "wrong-token",
                    refresh_token: "wrong-refresh",
                    expires_at: 1234567,
                    user: { id: "wrong", email: "wrong", github_username: "wrong" },
                },
            }));
            // Send the correct response
            mockWsInstance.emit("message", JSON.stringify({
                type: "auth_exchange_response",
                requestId: "auth_test-uuid-1234",
                payload: {
                    access_token: "correct-token",
                    refresh_token: "correct-refresh",
                    expires_at: 1707666000,
                    user: { id: "correct", email: "correct@test.com", github_username: "correct" },
                },
            }));
            const result = await promise;
            expect(result.access_token).toBe("correct-token");
        });
    });
    describe("refreshTokenViaGateway", () => {
        it("should send token_refresh message", async () => {
            const promise = refreshTokenViaGateway("my-refresh-token");
            mockWsInstance.emit("open");
            expect(mockWsInstance.send).toHaveBeenCalledWith(JSON.stringify({
                type: "token_refresh",
                requestId: "refresh_test-uuid-1234",
                payload: { refresh_token: "my-refresh-token" },
            }));
            mockWsInstance.emit("message", JSON.stringify({
                type: "token_refresh_response",
                requestId: "refresh_test-uuid-1234",
                payload: {
                    access_token: "new-at",
                    refresh_token: "new-rt",
                    expires_at: 1707752400,
                },
            }));
            const result = await promise;
            expect(result.access_token).toBe("new-at");
            expect(result.refresh_token).toBe("new-rt");
            expect(result.expires_at).toBe(1707752400);
        });
        it("should handle refresh error response", async () => {
            const promise = refreshTokenViaGateway("expired-refresh-token");
            mockWsInstance.emit("open");
            mockWsInstance.emit("message", JSON.stringify({
                type: "token_refresh_response",
                requestId: "refresh_test-uuid-1234",
                error: {
                    code: "INVALID_REFRESH_TOKEN",
                    message: "Refresh token is invalid or expired",
                },
            }));
            await expect(promise).rejects.toThrow("Token refresh failed: Refresh token is invalid or expired");
        });
        it("should timeout if no response", async () => {
            const promise = refreshTokenViaGateway("timeout-token");
            mockWsInstance.emit("open");
            vi.advanceTimersByTime(30_001);
            await expect(promise).rejects.toThrow("Auth request timed out after 30000ms");
        });
    });
});
//# sourceMappingURL=gateway-auth.test.js.map