import nock from "nock";
import yargs from "yargs/yargs";
import linkCommand from "../../cmds/link.js";
import { setupTestEnvironment, cleanupTest, setupAuthenticatedNock, RequestCapture, TEST_API_BASE, TEST_ACCOUNT_NAME, TEST_PROJECT_NAME, TEST_AUTH_TOKEN, } from "./test-utils.js";
jest.doMock("../../common/output.js", () => {
    const originalModule = jest.requireActual("../../common/output.js");
    return {
        ...originalModule,
        __esModule: true,
        printCriticalFailureToConsoleAndExit: jest.fn().mockImplementation(() => {
            throw new Error("Process would exit");
        }),
    };
});
jest.mock("../../common/validators/file-system-validator.js", () => ({
    ZuploProjectValidator: jest.fn().mockImplementation(() => ({
        validate: jest.fn().mockResolvedValue(true),
    })),
}));
jest.mock("../../link/populate.js", () => ({
    pullSystemConfig: jest.fn().mockResolvedValue(undefined),
    safeMergeConfig: jest.fn().mockResolvedValue(undefined),
}));
async function executeLinkCommand(args) {
    const yargsInstance = yargs([])
        .command(linkCommand)
        .help(false)
        .version(false)
        .exitProcess(false);
    const commandArgs = ["link"];
    if (args.account) {
        commandArgs.push("--account", args.account);
    }
    if (args.project) {
        commandArgs.push("--project", args.project);
    }
    if (args["api-key"]) {
        commandArgs.push("--api-key", args["api-key"]);
    }
    if (args.environment) {
        commandArgs.push("--environment", args.environment);
    }
    if (args.dir) {
        commandArgs.push("--dir", args.dir);
    }
    return await yargsInstance.parse(commandArgs);
}
const mockPrintResult = jest.mocked(require("../../common/output.js").printResultToConsoleAndExitGracefully);
const mockPrintCriticalFailure = jest.mocked(require("../../common/output.js").printCriticalFailureToConsoleAndExit);
describe("Link Command Integration Tests", () => {
    let requestCapture;
    beforeEach(() => {
        setupTestEnvironment();
        requestCapture = new RequestCapture();
        nock.disableNetConnect();
        jest.clearAllMocks();
    });
    afterEach(() => {
        cleanupTest();
        requestCapture.clear();
    });
    describe("Link with project and environment specified", () => {
        it("should skip API calls when project and environment are provided", async () => {
            await executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                environment: "development",
                dir: ".",
            });
            expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining(`Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`));
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toEqual([]);
        });
    });
    describe("Link with automatic project selection", () => {
        it("should intercept GET request to list projects", async () => {
            const mockProjectsResponse = {
                data: [
                    {
                        name: TEST_PROJECT_NAME,
                        accountName: TEST_ACCOUNT_NAME,
                        description: "Test project",
                        createdAt: "2024-01-01T00:00:00Z",
                    },
                ],
            };
            const mockEnvironmentsResponse = {
                data: [
                    {
                        name: "development",
                        environmentType: "development",
                        branchName: "main",
                        accountName: TEST_ACCOUNT_NAME,
                        projectName: TEST_PROJECT_NAME,
                    },
                ],
            };
            const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .reply(200, mockProjectsResponse);
            const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            })
                .reply(200, mockEnvironmentsResponse);
            [projectsScope, environmentsScope].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(projectsScope.isDone()).toBe(true);
            expect(environmentsScope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining(`Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`));
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-automatic-selection-requests");
        });
        it("should handle multiple projects and prompt selection", async () => {
            const mockProjectsResponse = {
                data: [
                    { name: "project-1", accountName: TEST_ACCOUNT_NAME },
                    { name: "project-2", accountName: TEST_ACCOUNT_NAME },
                ],
            };
            const mockEnvironmentsResponse = {
                data: [
                    {
                        name: "development",
                        environmentType: "development",
                        branchName: "main",
                        accountName: TEST_ACCOUNT_NAME,
                        projectName: "project-1",
                    },
                ],
            };
            const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .reply(200, mockProjectsResponse);
            const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: "project-1",
            })
                .reply(200, mockEnvironmentsResponse);
            [projectsScope, environmentsScope].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(projectsScope.isDone()).toBe(true);
            expect(environmentsScope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-multiple-projects-requests");
        });
    });
    describe("Link with environment creation", () => {
        it("should create development environment when none exists", async () => {
            const mockProjectsResponse = {
                data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
            };
            const mockEmptyEnvironmentsResponse = { data: [] };
            const mockCreatedEnvironment = {
                name: "development",
                environmentType: "development",
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            };
            const mockEnvironmentsAfterCreate = {
                data: [mockCreatedEnvironment],
            };
            const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .reply(200, mockProjectsResponse);
            const environmentsScope1 = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            })
                .reply(200, mockEmptyEnvironmentsResponse);
            const createEnvironmentScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post("/v1/environments")
                .reply(201, mockCreatedEnvironment);
            const environmentsScope2 = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            })
                .reply(200, mockEnvironmentsAfterCreate);
            [
                projectsScope,
                environmentsScope1,
                createEnvironmentScope,
                environmentsScope2,
            ].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(projectsScope.isDone()).toBe(true);
            expect(environmentsScope1.isDone()).toBe(true);
            expect(createEnvironmentScope.isDone()).toBe(true);
            expect(environmentsScope2.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-create-environment-requests");
            const createRequest = capturedRequests.find((req) => req.method === "POST" && req.path === "/v1/environments");
            expect(createRequest?.body).toEqual({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
                environmentType: "development",
            });
        });
    });
    describe("Error handling", () => {
        it("should handle projects list failure", async () => {
            const errorResponse = {
                error: "Unauthorized",
                message: "Invalid API key",
                statusCode: 401,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .reply(401, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await expect(executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            })).rejects.toThrow("Process would exit");
            expect(scope.isDone()).toBe(true);
            expect(mockPrintCriticalFailure).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-projects-error-requests");
        });
        it("should handle environments list failure", async () => {
            const mockProjectsResponse = {
                data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
            };
            const errorResponse = {
                error: "Forbidden",
                message: "Access denied to project",
                statusCode: 403,
            };
            const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .reply(200, mockProjectsResponse);
            const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            })
                .reply(403, errorResponse);
            [projectsScope, environmentsScope].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await expect(executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            })).rejects.toThrow("Process would exit");
            expect(projectsScope.isDone()).toBe(true);
            expect(environmentsScope.isDone()).toBe(true);
            expect(mockPrintCriticalFailure).toHaveBeenCalled();
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-environments-error-requests");
        });
    });
    describe("Request validation", () => {
        it("should include correct headers for API requests", async () => {
            const mockProjectsResponse = {
                data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
            };
            const mockEnvironmentsResponse = {
                data: [
                    {
                        name: "development",
                        environmentType: "development",
                        branchName: "main",
                        accountName: TEST_ACCOUNT_NAME,
                        projectName: TEST_PROJECT_NAME,
                    },
                ],
            };
            const projectsScope = nock(TEST_API_BASE)
                .get("/v1/projects")
                .query({ accountName: TEST_ACCOUNT_NAME })
                .matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
                .reply(200, mockProjectsResponse);
            const environmentsScope = nock(TEST_API_BASE)
                .get("/v1/environments")
                .query({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
            })
                .matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
                .reply(200, mockEnvironmentsResponse);
            [projectsScope, environmentsScope].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeLinkCommand({
                account: TEST_ACCOUNT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(projectsScope.isDone()).toBe(true);
            expect(environmentsScope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("link-headers-validation");
        });
    });
});
//# sourceMappingURL=link.integration.test.js.map