// Task 583 — Installer must seed permissions.defaultMode=bypassPermissions
// and permissions.allow=["*"] into the brand-scoped settings.json so
// claude.ai/code sessions never fall through to the Anthropic remote
// auto-classifier. Existing top-level keys must be preserved; an
// already-correct file must be a true no-op (mtime unchanged).
import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, readFileSync, writeFileSync, statSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { seedBypassPermissionsSettings, assertBypassPermissionsSeed, BYPASS_PERMISSIONS_BLOCK } from "../permissions-seed.js";
function freshDir() {
    return mkdtempSync(join(tmpdir(), "t583-"));
}
test("empty target: creates settings.json with the permissions block", () => {
    const dir = freshDir();
    try {
        const result = seedBypassPermissionsSettings(dir);
        assert.equal(result.action, "seeded");
        assert.equal(result.path, join(dir, "settings.json"));
        const parsed = JSON.parse(readFileSync(result.path, "utf-8"));
        assert.deepEqual(parsed, { permissions: { defaultMode: "bypassPermissions", allow: ["*"], deny: [] } });
        assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("existing keys preserved verbatim; permissions added", () => {
    const dir = freshDir();
    try {
        const settingsPath = join(dir, "settings.json");
        const existing = {
            enabledPlugins: { "memory@claude-plugins-official": true },
            extraKnownMarketplaces: { "claude-plugins-official": { source: { source: "github", repo: "anthropics/claude-plugins-official" } } },
            inputNeededNotifEnabled: false,
            agentPushNotifEnabled: false,
            model: "opus",
        };
        writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
        const result = seedBypassPermissionsSettings(dir);
        assert.equal(result.action, "seeded");
        const parsed = JSON.parse(readFileSync(settingsPath, "utf-8"));
        assert.deepEqual(parsed.enabledPlugins, existing.enabledPlugins);
        assert.deepEqual(parsed.extraKnownMarketplaces, existing.extraKnownMarketplaces);
        assert.equal(parsed.inputNeededNotifEnabled, false);
        assert.equal(parsed.agentPushNotifEnabled, false);
        assert.equal(parsed.model, "opus");
        assert.deepEqual(parsed.permissions, { defaultMode: "bypassPermissions", allow: ["*"], deny: [] });
        assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("idempotent: already-correct block triggers no write", () => {
    const dir = freshDir();
    try {
        const settingsPath = join(dir, "settings.json");
        writeFileSync(settingsPath, JSON.stringify({ model: "opus", permissions: { defaultMode: "bypassPermissions", allow: ["*"], deny: [] } }, null, 2));
        const before = statSync(settingsPath).mtimeMs;
        // Small busy-wait so a same-millisecond write would be detectable on
        // filesystems with millisecond mtime granularity.
        const target = Date.now() + 15;
        while (Date.now() < target) { /* spin */ }
        const result = seedBypassPermissionsSettings(dir);
        assert.equal(result.action, "noop");
        const after = statSync(settingsPath).mtimeMs;
        assert.equal(after, before, "mtime must not change on noop");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("malformed JSON: overwrites with the seeded block", () => {
    const dir = freshDir();
    try {
        const settingsPath = join(dir, "settings.json");
        writeFileSync(settingsPath, "{ not json");
        const result = seedBypassPermissionsSettings(dir);
        assert.equal(result.action, "seeded");
        assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("assert: missing file reports missing", () => {
    const dir = freshDir();
    try {
        assert.equal(assertBypassPermissionsSeed(dir).status, "missing");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("assert: partial block (no wildcard) reports missing", () => {
    const dir = freshDir();
    try {
        writeFileSync(join(dir, "settings.json"), JSON.stringify({ permissions: { defaultMode: "default", allow: [], deny: [] } }));
        assert.equal(assertBypassPermissionsSeed(dir).status, "missing");
    }
    finally {
        rmSync(dir, { recursive: true, force: true });
    }
});
test("BYPASS_PERMISSIONS_BLOCK frozen literal matches expected shape", () => {
    assert.equal(BYPASS_PERMISSIONS_BLOCK.defaultMode, "bypassPermissions");
    assert.deepEqual([...BYPASS_PERMISSIONS_BLOCK.allow], ["*"]);
    assert.deepEqual([...BYPASS_PERMISSIONS_BLOCK.deny], []);
    assert.ok(Object.isFrozen(BYPASS_PERMISSIONS_BLOCK));
});
