import nock from "nock";
import yargs from "yargs/yargs";
import deployCommand from "../../cmds/deploy.js";
import { setupTestEnvironment, cleanupTest, setupAuthenticatedNock, RequestCapture, TEST_API_BASE, TEST_ACCOUNT_NAME, TEST_PROJECT_NAME, TEST_AUTH_TOKEN, } from "./test-utils.js";
jest.mock("../../common/validators/file-system-validator.js", () => ({
    validDeployDirectoryValidator: {
        validate: jest.fn().mockResolvedValue(true),
    },
}));
jest.mock("../../deploy/archive.js", () => ({
    archive: jest.fn().mockResolvedValue({
        tarball: "/tmp/test-archive.tar.gz",
        metadata: {
            branch: "main",
            sha: "abc123",
            repoUrl: "https://github.com/user/repo.git",
        },
    }),
    generateMetadata: jest.fn().mockResolvedValue({
        branch: "main",
        sha: "abc123",
        repoUrl: "https://github.com/user/repo.git",
    }),
}));
jest.mock("../../deploy/file-upload.js", () => ({
    upload: jest.fn(async ({ uploadUrl, tarballPath, deploymentId, ...payload }) => {
        const response = await fetch(uploadUrl, {
            method: "PUT",
            body: "mock-tarball-content",
        });
        return {
            ok: response.ok,
            status: response.status,
        };
    }),
}));
jest.mock("../../deploy/poll-deployment.js", () => ({
    pollDeployment: jest.fn().mockResolvedValue({
        url: "https://test-project-main.zuplo.app",
        logUrl: "https://portal.zuplo.com/logs/deployment-123",
    }),
    pollBuild: jest.fn().mockResolvedValue({
        conditionType: "Complete",
    }),
}));
jest.mock("../../link/populate.js", () => ({
    pullSystemConfig: jest.fn().mockResolvedValue(undefined),
}));
jest.mock("../../deploy/environments.js", () => ({
    retrieveOrCreateEnvironment: jest.fn().mockResolvedValue({
        name: "development",
        type: "development",
    }),
    UnableToAutoLinkToExistingProject: class extends Error {
    },
}));
jest.mock("node:fs", () => ({
    existsSync: jest.fn().mockReturnValue(false),
    readFileSync: jest.fn().mockReturnValue(Buffer.from("mock-tarball-content")),
    writeFileSync: jest.fn(),
}));
async function executeDeployCommand(args) {
    const yargsInstance = yargs([])
        .command(deployCommand)
        .help(false)
        .version(false)
        .exitProcess(false);
    const commandArgs = ["deploy"];
    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["self-hosted-endpoint"]) {
        commandArgs.push("--self-hosted-endpoint", args["self-hosted-endpoint"]);
    }
    if (args.dir) {
        commandArgs.push("--dir", args.dir);
    }
    return await yargsInstance.parse(commandArgs);
}
const mockPrintResult = jest.mocked(require("../../common/output.js").printResultToConsoleAndExitGracefully);
describe("Deploy Command Integration Tests", () => {
    let requestCapture;
    beforeEach(() => {
        setupTestEnvironment();
        requestCapture = new RequestCapture();
        nock.disableNetConnect();
        jest.clearAllMocks();
    });
    afterEach(() => {
        cleanupTest();
        requestCapture.clear();
    });
    describe("SaaS deployment", () => {
        it("should intercept POST request to get source upload URL", async () => {
            const mockUploadUrlResponse = {
                uploadUrl: "https://storage.example.com/upload/abc123",
                deploymentId: "deployment-456",
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post("/v1/deployments/source-url")
                .reply(200, mockUploadUrlResponse);
            const uploadScope = nock("https://storage.example.com")
                .put("/upload/abc123")
                .reply(200, { message: "Upload successful" });
            [scope, uploadScope].forEach((s) => {
                s.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeDeployCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(scope.isDone()).toBe(true);
            expect(uploadScope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining("Deployed to https://test-project-main.zuplo.app"), expect.any(Object));
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("deploy-saas-requests");
            const sourceUrlRequest = capturedRequests.find((req) => req.path === "/v1/deployments/source-url");
            expect(sourceUrlRequest?.method).toBe("POST");
            expect(sourceUrlRequest?.body).toEqual({
                accountName: TEST_ACCOUNT_NAME,
                projectName: TEST_PROJECT_NAME,
                environment: "main",
                repositoryUrl: "https://github.com/user/repo.git",
                sha: "abc123",
            });
        });
        it("should handle upload URL request failure", async () => {
            const errorResponse = {
                error: "Forbidden",
                message: "Insufficient permissions",
                statusCode: 403,
            };
            const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
                .post("/v1/deployments/source-url")
                .reply(403, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await expect(executeDeployCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            })).rejects.toThrow("Process would exit");
            expect(scope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("deploy-saas-error-requests");
        });
    });
    describe("Self-hosted deployment", () => {
        it("should intercept POST request to self-hosted build endpoint", async () => {
            const selfHostedEndpoint = "https://my-zuplo.company.com";
            const mockBuildResponse = {
                buildName: "build-789",
            };
            const buildScope = setupAuthenticatedNock(nock(selfHostedEndpoint))
                .post("/v1/deployments/build")
                .reply(200, mockBuildResponse);
            const deploymentScope = setupAuthenticatedNock(nock(selfHostedEndpoint))
                .get("/v1/deployments/test-project-main")
                .reply(200, {
                deploymentUrl: "https://my-zuplo.company.com/test-project-main",
            });
            [buildScope, deploymentScope].forEach((scope) => {
                scope.on("request", (req, interceptor, body) => {
                    requestCapture.capture(req, interceptor, body);
                });
            });
            await executeDeployCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "self-hosted-endpoint": selfHostedEndpoint,
                dir: ".",
            });
            expect(buildScope.isDone()).toBe(true);
            expect(deploymentScope.isDone()).toBe(true);
            expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining("Deployed to https://my-zuplo.company.com/test-project-main"), expect.any(Object));
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("deploy-self-hosted-requests");
            const buildRequest = capturedRequests.find((req) => req.path === "/v1/deployments/build");
            expect(buildRequest?.method).toBe("POST");
            expect(buildRequest?.body).toBeDefined();
        }, 60000);
        it("should handle self-hosted build failure", async () => {
            const selfHostedEndpoint = "https://my-zuplo.company.com";
            const errorResponse = {
                error: "Bad Request",
                message: "Invalid project configuration",
                statusCode: 400,
            };
            const scope = setupAuthenticatedNock(nock(selfHostedEndpoint))
                .post("/v1/deployments/build")
                .reply(400, errorResponse);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeDeployCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                "self-hosted-endpoint": selfHostedEndpoint,
                dir: ".",
            });
            expect(scope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("deploy-self-hosted-error-requests");
        }, 60000);
    });
    describe("Request validation", () => {
        it("should include correct headers for SaaS deployment", async () => {
            const mockResponse = {
                uploadUrl: "https://storage.example.com/upload/abc123",
                deploymentId: "deployment-456",
            };
            const scope = nock(TEST_API_BASE)
                .post("/v1/deployments/source-url")
                .matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
                .reply(200, mockResponse);
            nock("https://storage.example.com").put("/upload/abc123").reply(200);
            scope.on("request", (req, interceptor, body) => {
                requestCapture.capture(req, interceptor, body);
            });
            await executeDeployCommand({
                account: TEST_ACCOUNT_NAME,
                project: TEST_PROJECT_NAME,
                "api-key": TEST_AUTH_TOKEN,
                dir: ".",
            });
            expect(scope.isDone()).toBe(true);
            const capturedRequests = requestCapture.getRequests();
            expect(capturedRequests).toMatchSnapshot("deploy-headers-validation");
        });
    });
});
//# sourceMappingURL=deploy.integration.test.js.map