import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { mkdtemp, rm, readFile, stat } from "node:fs/promises";
import { tmpdir, platform } from "node:os";
import { join } from "node:path";
const VALID_TOKENS = {
    machine_key: "550e8400-e29b-41d4-a716-446655440000",
    access_token: "eyJ.test.token",
    refresh_token: "refresh_abc123",
    expires_at: 1707666000,
    user_id: "github|12345",
};
describe("token-storage", () => {
    let tempDir;
    let authPath;
    beforeEach(async () => {
        tempDir = await mkdtemp(join(tmpdir(), "pocketcoder-auth-test-"));
        authPath = join(tempDir, "auth.json");
    });
    afterEach(async () => {
        vi.restoreAllMocks();
        await rm(tempDir, { recursive: true, force: true });
    });
    async function importModule() {
        vi.resetModules();
        vi.doMock("../../utils/paths.js", () => ({
            getAuthPath: () => authPath,
        }));
        return await import("../token-storage.js");
    }
    describe("saveTokens", () => {
        it("should save tokens with secure permissions", async () => {
            const { saveTokens } = await importModule();
            await saveTokens(VALID_TOKENS);
            const content = await readFile(authPath, "utf-8");
            const parsed = JSON.parse(content);
            expect(parsed).toEqual(VALID_TOKENS);
            if (platform() !== "win32") {
                const fileStat = await stat(authPath);
                // 0o600 = owner read+write only
                const mode = fileStat.mode & 0o777;
                expect(mode).toBe(0o600);
            }
        });
        it("should write valid JSON with all fields", async () => {
            const { saveTokens } = await importModule();
            await saveTokens(VALID_TOKENS);
            const content = await readFile(authPath, "utf-8");
            const parsed = JSON.parse(content);
            expect(parsed.machine_key).toBe(VALID_TOKENS.machine_key);
            expect(parsed.access_token).toBe(VALID_TOKENS.access_token);
            expect(parsed.refresh_token).toBe(VALID_TOKENS.refresh_token);
            expect(parsed.expires_at).toBe(VALID_TOKENS.expires_at);
            expect(parsed.user_id).toBe(VALID_TOKENS.user_id);
        });
        it("should overwrite existing tokens", async () => {
            const { saveTokens, loadTokens } = await importModule();
            await saveTokens(VALID_TOKENS);
            const updated = {
                ...VALID_TOKENS,
                access_token: "new_token",
                expires_at: 9999999999,
            };
            await saveTokens(updated);
            const loaded = await loadTokens();
            expect(loaded).toEqual(updated);
        });
    });
    describe("loadTokens", () => {
        it("should load tokens from file", async () => {
            const { saveTokens, loadTokens } = await importModule();
            await saveTokens(VALID_TOKENS);
            const loaded = await loadTokens();
            expect(loaded).toEqual(VALID_TOKENS);
        });
        it("should return null when file does not exist", async () => {
            const { loadTokens } = await importModule();
            const loaded = await loadTokens();
            expect(loaded).toBeNull();
        });
        it("should return null for invalid JSON", async () => {
            const { loadTokens } = await importModule();
            const { writeFile } = await import("node:fs/promises");
            await writeFile(authPath, "not valid json");
            const loaded = await loadTokens();
            expect(loaded).toBeNull();
        });
        it("should validate token structure on load", async () => {
            const { loadTokens } = await importModule();
            const { writeFile } = await import("node:fs/promises");
            // Missing required fields
            await writeFile(authPath, JSON.stringify({ machine_key: "test" }));
            expect(await loadTokens()).toBeNull();
            // Wrong types
            await writeFile(authPath, JSON.stringify({
                machine_key: "test",
                access_token: "test",
                refresh_token: "test",
                expires_at: "not-a-number",
                user_id: "test",
            }));
            expect(await loadTokens()).toBeNull();
            // Valid structure
            await writeFile(authPath, JSON.stringify(VALID_TOKENS));
            expect(await loadTokens()).toEqual(VALID_TOKENS);
        });
    });
    describe("hasValidTokens", () => {
        it("should return true when tokens exist and are not expired", async () => {
            const { saveTokens, hasValidTokens } = await importModule();
            const futureTokens = {
                ...VALID_TOKENS,
                expires_at: Math.floor(Date.now() / 1000) + 3600,
            };
            await saveTokens(futureTokens);
            expect(await hasValidTokens()).toBe(true);
        });
        it("should return false when tokens are expired", async () => {
            const { saveTokens, hasValidTokens } = await importModule();
            const expiredTokens = {
                ...VALID_TOKENS,
                expires_at: Math.floor(Date.now() / 1000) - 100,
            };
            await saveTokens(expiredTokens);
            expect(await hasValidTokens()).toBe(false);
        });
        it("should return false when no tokens exist", async () => {
            const { hasValidTokens } = await importModule();
            expect(await hasValidTokens()).toBe(false);
        });
    });
    describe("clearTokens", () => {
        it("should clear tokens by removing file", async () => {
            const { saveTokens, clearTokens, loadTokens } = await importModule();
            await saveTokens(VALID_TOKENS);
            await clearTokens();
            const loaded = await loadTokens();
            expect(loaded).toBeNull();
        });
        it("should not throw when file does not exist", async () => {
            const { clearTokens } = await importModule();
            await expect(clearTokens()).resolves.toBeUndefined();
        });
    });
});
//# sourceMappingURL=token-storage.test.js.map