import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { detectCredentialPrompt, requestCredential, resolveCredential, hasPendingCredential, clearPendingCredentials, } from "../credentials.js";
vi.mock("../../../utils/logger.js", () => ({
    logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
}));
describe("git/credentials", () => {
    beforeEach(() => {
        vi.useFakeTimers();
        clearPendingCredentials();
    });
    afterEach(() => {
        clearPendingCredentials();
        vi.useRealTimers();
    });
    describe("detectCredentialPrompt", () => {
        it("should detect password prompt", () => {
            const result = detectCredentialPrompt("Password for 'https://github.com':");
            expect(result).toEqual({
                type: "password",
                prompt: "Password for 'https://github.com':",
            });
        });
        it("should detect passphrase prompt", () => {
            const result = detectCredentialPrompt("Enter passphrase for key '/home/user/.ssh/id_rsa':");
            expect(result).toEqual({
                type: "passphrase",
                prompt: "Enter passphrase for key '/home/user/.ssh/id_rsa':",
            });
        });
        it("should detect username prompt", () => {
            const result = detectCredentialPrompt("Username for 'https://github.com':");
            expect(result).toEqual({
                type: "username",
                prompt: "Username for 'https://github.com':",
            });
        });
        it("should detect PIN prompt", () => {
            const result = detectCredentialPrompt("Enter PIN for authenticator:");
            expect(result).toEqual({
                type: "pin",
                prompt: "Enter PIN for authenticator:",
            });
        });
        it("should return null for non-credential output", () => {
            const result = detectCredentialPrompt("Enumerating objects: 5, done.");
            expect(result).toBeNull();
        });
        it("should be case-insensitive", () => {
            const result = detectCredentialPrompt("password:");
            expect(result).not.toBeNull();
            expect(result.type).toBe("password");
        });
    });
    describe("requestCredential", () => {
        it("should forward prompt to client", () => {
            const send = vi.fn();
            const requestId = "req-123";
            // Don't await - just start the request
            const promise = requestCredential(requestId, "password", "Password:", send);
            expect(send).toHaveBeenCalledOnce();
            const event = send.mock.calls[0][0];
            expect(event.type).toBe("credential_prompt");
            expect(event.requestId).toBe(requestId);
            expect(event.payload.promptType).toBe("password");
            expect(event.payload.prompt).toBe("Password:");
            // Clean up
            resolveCredential(requestId, "test", false);
            return promise;
        });
        it("should write response to PTY (resolve with value)", async () => {
            const send = vi.fn();
            const requestId = "req-456";
            const promise = requestCredential(requestId, "password", "Password:", send);
            // Simulate client sending credential_response
            const resolved = resolveCredential(requestId, "my-secret-password", false);
            expect(resolved).toBe(true);
            const response = await promise;
            expect(response.value).toBe("my-secret-password");
            expect(response.cancelled).toBe(false);
        });
        it("should handle timeout", async () => {
            const send = vi.fn();
            const requestId = "req-timeout";
            const promise = requestCredential(requestId, "password", "Password:", send);
            // Advance past timeout (90s)
            vi.advanceTimersByTime(90_000);
            const response = await promise;
            expect(response.cancelled).toBe(true);
            expect(response.value).toBe("");
        });
        it("should handle cancelled credentials", async () => {
            const send = vi.fn();
            const requestId = "req-cancel";
            const promise = requestCredential(requestId, "passphrase", "Enter passphrase:", send);
            resolveCredential(requestId, "", true);
            const response = await promise;
            expect(response.cancelled).toBe(true);
            expect(response.value).toBe("");
        });
    });
    describe("resolveCredential", () => {
        it("should return false for unknown request", () => {
            const result = resolveCredential("unknown-id", "value", false);
            expect(result).toBe(false);
        });
        it("should clear the timeout when resolved", async () => {
            const send = vi.fn();
            const requestId = "req-clear";
            const promise = requestCredential(requestId, "password", "Password:", send);
            resolveCredential(requestId, "secret", false);
            await promise;
            // Advancing time past timeout should have no effect (no double resolution)
            expect(hasPendingCredential(requestId)).toBe(false);
        });
    });
    describe("hasPendingCredential", () => {
        it("should return true for pending requests", () => {
            const send = vi.fn();
            requestCredential("req-pending", "password", "Password:", send);
            expect(hasPendingCredential("req-pending")).toBe(true);
            // Clean up
            resolveCredential("req-pending", "", true);
        });
        it("should return false after resolution", async () => {
            const send = vi.fn();
            const promise = requestCredential("req-done", "password", "Password:", send);
            resolveCredential("req-done", "val", false);
            await promise;
            expect(hasPendingCredential("req-done")).toBe(false);
        });
    });
    describe("clearPendingCredentials", () => {
        it("should resolve all pending with cancelled", async () => {
            const send = vi.fn();
            const p1 = requestCredential("req-a", "password", "Password:", send);
            const p2 = requestCredential("req-b", "username", "Username:", send);
            clearPendingCredentials();
            const r1 = await p1;
            const r2 = await p2;
            expect(r1.cancelled).toBe(true);
            expect(r2.cancelled).toBe(true);
        });
    });
});
//# sourceMappingURL=credentials.test.js.map