import nock from "nock";
import yargs from "yargs/yargs";
import infoCommand from "../../cmds/info.js";
import { cleanupTest, setupAuthenticatedNock, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_API_BASE, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
const TEST_ACCOUNT = TEST_ACCOUNT_NAME;
const TEST_PROJECT = TEST_PROJECT_NAME;
jest.mock("../../common/read-linked-config.js", () => ({
    __esModule: true,
    readLinkedConfig: jest.fn().mockResolvedValue({}),
    confirmLinkedValue: jest.fn().mockResolvedValue(true),
    USE_LINKED_DETAILS: "useLinkedDetails",
    ignoreLinkedDetails: jest.fn(),
}));
const { readLinkedConfig } = jest.requireMock("../../common/read-linked-config.js");
async function executeInfoCommand(args) {
    const yargsInstance = yargs([])
        .command(infoCommand)
        .help(false)
        .version(false)
        .exitProcess(false);
    const commandArgs = ["info"];
    if (args["api-key"]) {
        commandArgs.push("--api-key", args["api-key"]);
    }
    return await yargsInstance.parse(commandArgs);
}
const mockPrintResult = jest.mocked(require("../../common/output.js").printResultToConsoleAndExitGracefully);
const mockPrintCriticalFailure = jest.mocked(require("../../common/output.js").printCriticalFailureToConsoleAndExit);
const mockPrintWarning = jest.mocked(require("../../common/output.js").printWarningToConsole);
describe("Info Command Integration Tests", () => {
    beforeEach(() => {
        setupTestEnvironment();
        nock.cleanAll();
        nock.disableNetConnect();
        jest.clearAllMocks();
        readLinkedConfig.mockResolvedValue({});
    });
    afterEach(() => {
        cleanupTest();
    });
    it("should show 'no project linked' when .env.zuplo is missing", async () => {
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain("No project linked");
        expect(output).toContain("zuplo link");
    });
    it("should show 'no project linked' when unauthenticated and not linked", async () => {
        await executeInfoCommand({});
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain("No project linked");
        expect(output).toContain("zuplo link");
        expect(mockPrintCriticalFailure).not.toHaveBeenCalled();
    });
    it("should show full project info when linked", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: TEST_PROJECT,
                    sourceRepoUrl: "https://github.com/josh-twist/josh-poc",
                    sourceControlProvider: "GITHUB",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain(`Project: ${TEST_PROJECT}`);
        expect(output).toContain(`Account: ${TEST_ACCOUNT}`);
        expect(output).toContain(`Portal: https://portal.zuplo.com/${TEST_ACCOUNT}/${TEST_PROJECT}`);
        expect(output).toContain("Environment Type: working-copy");
        expect(output).not.toContain("Environment Type: development");
        expect(output).toContain("Source Control: https://github.com/josh-twist/josh-poc");
    });
    it.each(["development", "working_copy", "working-copy"])("should display 'working-copy' label for ZUPLO_ENVIRONMENT_TYPE=%s", async (envType) => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: envType,
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: TEST_PROJECT,
                    sourceRepoUrl: null,
                    sourceControlProvider: "NONE",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain("Environment Type: working-copy");
    });
    it("should omit environment type when the linked value is whitespace-only", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "   ",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: TEST_PROJECT,
                    sourceRepoUrl: null,
                    sourceControlProvider: "NONE",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).not.toContain("Environment Type:");
    });
    it("should show source control deep link when no repo is connected", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "production",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: TEST_PROJECT,
                    sourceRepoUrl: null,
                    sourceControlProvider: "NONE",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain(`Source Control: none, connect at https://portal.zuplo.com/${TEST_ACCOUNT}/${TEST_PROJECT}/settings/source-control-settings`);
    });
    it("should omit environment type when not in linked config", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: TEST_PROJECT,
                    sourceRepoUrl: null,
                    sourceControlProvider: "NONE",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).not.toContain("Environment Type:");
    });
    it("should exit with error when API returns 401 and --api-key was used", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(401, {
            type: "https://httpproblems.com/http-status/401",
            title: "Unauthorized",
            status: 401,
            detail: "Invalid token",
        });
        await expect(executeInfoCommand({ "api-key": TEST_AUTH_TOKEN })).rejects.toThrow("Process would exit");
        expect(mockPrintCriticalFailure).toHaveBeenCalledWith("The provided --api-key was rejected. Check that it is valid and not expired, or run `zuplo login` to authenticate interactively.");
        expect(mockPrintResult).not.toHaveBeenCalled();
        expect(mockPrintWarning).not.toHaveBeenCalled();
    });
    it("should exit with error when API returns 401 and saved credentials were used", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(401, {
            type: "https://httpproblems.com/http-status/401",
            title: "Unauthorized",
            status: 401,
            detail: "Invalid token",
        });
        await expect(executeInfoCommand({})).rejects.toThrow("Process would exit");
        expect(mockPrintCriticalFailure).toHaveBeenCalledWith("Your saved credentials were rejected. They may be expired — run `zuplo login` to re-authenticate, or pass a valid --api-key.");
        expect(mockPrintResult).not.toHaveBeenCalled();
        expect(mockPrintWarning).not.toHaveBeenCalled();
    });
    it("should show local info with warning when API returns a server error", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(500, { error: "Internal Server Error" });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain(`Project: ${TEST_PROJECT}`);
        expect(output).toContain(`Account: ${TEST_ACCOUNT}`);
        expect(output).not.toContain("Source Control:");
        expect(mockPrintWarning).toHaveBeenCalledWith("Unable to fetch project details, some information may be missing");
    });
    it("should exit with error when API returns a non-401 4xx", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(403, { error: "Forbidden" });
        await expect(executeInfoCommand({ "api-key": TEST_AUTH_TOKEN })).rejects.toThrow("Process would exit");
        expect(mockPrintCriticalFailure).toHaveBeenCalledWith(`The Zuplo API returned 403 Forbidden. Verify the account "${TEST_ACCOUNT}" and your credentials.`);
        expect(mockPrintResult).not.toHaveBeenCalled();
        expect(mockPrintWarning).not.toHaveBeenCalled();
    });
    it("should show local info with warning on network error", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "development",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .replyWithError("ECONNREFUSED");
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain(`Project: ${TEST_PROJECT}`);
        expect(output).toContain(`Account: ${TEST_ACCOUNT}`);
        expect(output).not.toContain("Source Control:");
        expect(mockPrintWarning).toHaveBeenCalledWith("Unable to fetch project details, some information may be missing");
    });
    it("should warn and omit source control when linked project is not in API response", async () => {
        readLinkedConfig.mockResolvedValue({
            accountName: TEST_ACCOUNT,
            projectName: TEST_PROJECT,
            environmentType: "working_copy",
        });
        setupAuthenticatedNock(nock(TEST_API_BASE))
            .get(`/v1/projects`)
            .query({ accountName: TEST_ACCOUNT })
            .reply(200, {
            data: [
                {
                    name: "some-other-project",
                    sourceRepoUrl: "https://github.com/josh-twist/other",
                    sourceControlProvider: "GITHUB",
                },
            ],
        });
        await executeInfoCommand({ "api-key": TEST_AUTH_TOKEN });
        expect(mockPrintResult).toHaveBeenCalledTimes(1);
        const output = mockPrintResult.mock.calls[0][0];
        expect(output).toContain(`Project: ${TEST_PROJECT}`);
        expect(output).toContain(`Account: ${TEST_ACCOUNT}`);
        expect(output).not.toContain("Source Control:");
        expect(mockPrintWarning).toHaveBeenCalledWith(`Project "${TEST_PROJECT}" was not found in account "${TEST_ACCOUNT}". Run \`zuplo link\` to link a project.`);
    });
});
//# sourceMappingURL=info.integration.test.js.map