import nock from "nock";
import yargs from "yargs/yargs";
import tunnelCommand from "../../cmds/tunnel/index.js";
import { setupTestEnvironment, cleanupTest, setupAuthenticatedNock, RequestCapture, TEST_API_BASE, TEST_ACCOUNT_NAME, TEST_AUTH_TOKEN, } from "./test-utils.js";
async function executeTunnelCommand(subcommand, args) {
    const yargsInstance = yargs([])
        .command(tunnelCommand)
        .help(false)
        .version(false)
        .exitProcess(false);
    const commandArgs = ["tunnel", subcommand];
    if (args.account) {
        commandArgs.push("--account", args.account);
    }
    if (args["api-key"]) {
        commandArgs.push("--api-key", args["api-key"]);
    }
    if (args["tunnel-name"]) {
        commandArgs.push("--tunnel-name", args["tunnel-name"]);
    }
    if (args["tunnel-id"]) {
        commandArgs.push("--tunnel-id", args["tunnel-id"]);
    }
    return await yargsInstance.parse(commandArgs);
}
async function executeTunnelServicesCommand(subcommand, args) {
    const yargsInstance = yargs([])
        .command(tunnelCommand)
        .help(false)
        .version(false)
        .exitProcess(false);
    const commandArgs = ["tunnel", "services", subcommand];
    if (args.account) {
        commandArgs.push("--account", args.account);
    }
    if (args["api-key"]) {
        commandArgs.push("--api-key", args["api-key"]);
    }
    if (args["tunnel-id"]) {
        commandArgs.push("--tunnel-id", args["tunnel-id"]);
    }
    if (args["configuration-file"]) {
        commandArgs.push("--configuration-file", args["configuration-file"]);
    }
    return await yargsInstance.parse(commandArgs);
}
const mockPrintResult = jest.mocked(require("../../common/output.js").printResultToConsoleAndExitGracefully);
const mockPrintTable = jest.mocked(require("../../common/output.js").printTableToConsoleAndExitGracefully);
const mockPrintDiagnostics = jest.mocked(require("../../common/output.js").printDiagnosticsToConsole);
describe("Tunnel Command Integration Tests", () => {
    let requestCapture;
    beforeEach(() => {
        setupTestEnvironment();
        requestCapture = new RequestCapture();
        nock.disableNetConnect();
        jest.clearAllMocks();
    });
    afterEach(() => {
        cleanupTest();
        requestCapture.clear();
    });
    describe("Tunnel Create Command", () => {
        it("should intercept POST request to create tunnel", async () => {
            const testTunnelName = "my-test-tunnel";
            const mockResponse = {
                id: "tunnel-123",
                name: testTunnelName,
                token: "tunnel-token-abc123",
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .reply(201, mockResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("create", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-name": testTunnelName,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintTable).toHaveBeenCalledWith(mockResponse);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-create-requests");
            const request = capturedRequests[0];
            expect(request.method).toBe("POST");
            expect(request.body).toEqual({
                name: testTunnelName,
            });
        });
        it("should handle tunnel creation error", async () => {
            const testTunnelName = "invalid-tunnel";
            const errorResponse = {
                error: "Bad Request",
                message: "Tunnel name already exists",
                statusCode: 400,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .reply(400, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("create", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-name": testTunnelName,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-create-error-requests");
        });
    });
    describe("Tunnel List Command", () => {
        it("should intercept GET request to list tunnels", async () => {
            const mockResponse = {
                data: [
                    { id: "tunnel-123", name: "tunnel-1" },
                    { id: "tunnel-456", name: "tunnel-2" },
                ],
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .reply(200, mockResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("list", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
            });
            expect(scope.isDone()).toBe(true);
            const expectedTable = [
                { "tunnel-id": "tunnel-123", name: "tunnel-1" },
                { "tunnel-id": "tunnel-456", name: "tunnel-2" },
            ];
            expect(mockPrintTable).toHaveBeenCalledWith(expectedTable);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-list-requests");
        });
        it("should handle empty tunnels list", async () => {
            const mockResponse = { data: [] };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .reply(200, mockResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("list", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith("No tunnels found");
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-list-empty-requests");
        });
        it("should handle API error responses", async () => {
            const errorResponse = {
                error: "Forbidden",
                message: "Access denied",
                statusCode: 403,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .reply(403, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("list", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-list-error-requests");
        });
    });
    describe("Tunnel Delete Command", () => {
        it("should intercept DELETE request to delete tunnel", async () => {
            const tunnelId = "test-tunnel-123";
            const mockTeardownResponse = {
                id: "teardown-op-456",
                status: "in-progress",
            };
            const mockCompletedTeardown = {
                id: "teardown-op-456",
                status: "success",
                message: "Tunnel deleted successfully",
            };
            const deleteScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .delete(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}`)
                .reply(200, mockTeardownResponse);
            const pollScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/teardown-operations/teardown-op-456`)
                .reply(200, mockCompletedTeardown);
            deleteScope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            pollScope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("delete", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(deleteScope.isDone()).toBe(true);
            expect(pollScope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith("Tunnel test-tunnel-123 deleted successfully.");
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-delete-requests");
        });
        it("should handle tunnel deletion error", async () => {
            const tunnelId = "nonexistent-tunnel";
            const errorResponse = {
                error: "Not Found",
                message: "Tunnel not found",
                statusCode: 404,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .delete(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}`)
                .reply(404, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("delete", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-delete-error-requests");
        });
    });
    describe("Tunnel Describe Command", () => {
        it("should intercept GET request to describe tunnel", async () => {
            const tunnelId = "test-tunnel-123";
            const mockTunnelDetails = {
                id: tunnelId,
                name: "Test Tunnel",
                status: "active",
                endpoint: "https://test-tunnel.zuplo.dev",
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}`)
                .reply(200, mockTunnelDetails);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("describe", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintTable).toHaveBeenCalledWith(mockTunnelDetails);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-describe-requests");
        });
        it("should handle tunnel describe error", async () => {
            const tunnelId = "nonexistent-tunnel";
            const errorResponse = {
                error: "Not Found",
                message: "Tunnel not found",
                statusCode: 404,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}`)
                .reply(404, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("describe", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-describe-error-requests");
        });
    });
    describe("Tunnel Rotate Token Command", () => {
        it("should intercept POST request to rotate tunnel token", async () => {
            const tunnelId = "test-tunnel-123";
            const mockTokenResponse = {
                tunnelId: tunnelId,
                newToken: "new-token-abc123",
                message: "Token rotated successfully",
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/$rotate-token`)
                .reply(200, mockTokenResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("rotate-token", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintTable).toHaveBeenCalledWith(mockTokenResponse);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-rotate-token-requests");
        });
        it("should handle token rotation error", async () => {
            const tunnelId = "nonexistent-tunnel";
            const errorResponse = {
                error: "Forbidden",
                message: "Access denied",
                statusCode: 403,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/$rotate-token`)
                .reply(403, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("rotate-token", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-rotate-token-error-requests");
        });
    });
    describe("Tunnel Services Describe Command", () => {
        it("should intercept GET request to describe tunnel services", async () => {
            const tunnelId = "test-tunnel-123";
            const mockServicesResponse = {
                tunnelId: tunnelId,
                services: [
                    { name: "api-service", port: 3000, status: "running" },
                    { name: "web-service", port: 8080, status: "running" },
                ],
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/services-configuration`)
                .reply(200, mockServicesResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelServicesCommand("describe", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith(JSON.stringify(mockServicesResponse, null, 2));
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-services-describe-requests");
        });
        it("should handle services describe error", async () => {
            const tunnelId = "nonexistent-tunnel";
            const errorResponse = {
                error: "Not Found",
                message: "Tunnel not found",
                statusCode: 404,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/services-configuration`)
                .reply(404, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelServicesCommand("describe", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-services-describe-error-requests");
        });
    });
    describe("Tunnel Services Update Command", () => {
        it("should handle services update error due to file read failure", async () => {
            const tunnelId = "test-tunnel-123";
            const configFile = "/nonexistent/config.json";
            await expect(executeTunnelServicesCommand("update", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
                "configuration-file": configFile,
            })).rejects.toThrow("Process would exit");
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-services-update-file-error-requests");
        });
        it("should handle services update API error", async () => {
            const tunnelId = "test-tunnel-123";
            const tempConfigFile = "/tmp/test-config.json";
            const mockFs = require("node:fs/promises");
            const originalReadFile = mockFs.readFile;
            mockFs.readFile = jest.fn().mockResolvedValue('{"services": []}');
            const errorResponse = {
                error: "Bad Request",
                message: "Invalid configuration file",
                statusCode: 400,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .put(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels/${tunnelId}/services-configuration`)
                .reply(400, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelServicesCommand("update", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-id": tunnelId,
                "configuration-file": tempConfigFile,
            });
            expect(scope.isDone()).toBe(true);
            expect(mockPrintDiagnostics).toHaveBeenCalled();
            mockFs.readFile = originalReadFile;
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-services-update-error-requests");
        });
    });
    describe("Request validation", () => {
        it("should include correct headers for create request", async () => {
            const testTunnelName = "test-tunnel";
            const mockResponse = {
                id: "tunnel-123",
                name: testTunnelName,
                token: "tunnel-token-abc123",
            };
            const scope = nock(TEST_API_BASE)
                .post(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
                .matchHeader("content-type", "application/json")
                .reply(201, mockResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("create", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "tunnel-name": testTunnelName,
            });
            expect(scope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-create-headers-validation");
        });
        it("should include correct headers for list request", async () => {
            const mockResponse = { data: [{ id: "tunnel-123", name: "tunnel-1" }] };
            const scope = nock(TEST_API_BASE)
                .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/tunnels`)
                .matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
                .reply(200, mockResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeTunnelCommand("list", {
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
            });
            expect(scope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("tunnel-list-headers-validation");
            const request = capturedRequests[0];
            expect(request.method).toBe("GET");
            expect(request.body).toBeUndefined();
        });
    });
});
//# sourceMappingURL=tunnel.integration.test.js.map