import assert from "node:assert/strict";
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, test } from "node:test";
import { applyPersistedConfigUpdates, buildStructuredConfigPayload, getGlobalConfigPath, } from "../src/agent/editable-config.js";
import { createTestAgentConfig } from "./test-utils.js";
const tempDirs = [];
afterEach(async () => {
    await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
});
async function withUnsetEnvVars(names, callback) {
    const previous = new Map();
    for (const name of names) {
        previous.set(name, process.env[name]);
        delete process.env[name];
    }
    try {
        await callback();
    }
    finally {
        for (const [name, value] of previous) {
            if (value === undefined) {
                delete process.env[name];
            }
            else {
                process.env[name] = value;
            }
        }
    }
}
test("buildStructuredConfigPayload reports effective values and env overrides", async () => {
    await withUnsetEnvVars(["MAX_STEPS", "MODEL", "ENABLE_DYNAMIC_PROMPT"], async () => {
        const home = await mkdtemp(path.join(os.tmpdir(), "minicode-editable-config-"));
        const workspace = await mkdtemp(path.join(os.tmpdir(), "minicode-editable-ws-"));
        tempDirs.push(home, workspace);
        await applyPersistedConfigUpdates({
            minicodeHome: home,
            updates: {
                maxSteps: 77,
                model: "global-model",
            },
        });
        process.env.MAX_STEPS = "120";
        const payload = await buildStructuredConfigPayload({
            ...createTestAgentConfig(workspace),
            maxSteps: 120,
            model: "global-model",
        }, home);
        assert.equal(payload.configPath, path.join(home, ".env"));
        const maxSteps = payload.entries.find((entry) => entry.key === "maxSteps");
        assert.equal(maxSteps?.effectiveValue, 120);
        assert.equal(maxSteps?.persistedValue, 77);
        assert.equal(maxSteps?.envValue, "120");
        assert.equal(maxSteps?.envSource, "process");
        assert.equal(maxSteps?.envSourcePath, null);
        assert.equal(maxSteps?.overriddenByEnv, true);
        const model = payload.entries.find((entry) => entry.key === "model");
        assert.equal(model?.effectiveValue, "global-model");
        assert.equal(model?.persistedValue, "global-model");
        assert.equal(model?.overriddenByEnv, false);
    });
});
test("buildStructuredConfigPayload reports home dotenv env source", async () => {
    await withUnsetEnvVars(["MAX_STEPS"], async () => {
        const home = await mkdtemp(path.join(os.tmpdir(), "minicode-editable-config-"));
        const workspace = await mkdtemp(path.join(os.tmpdir(), "minicode-editable-ws-"));
        tempDirs.push(home, workspace);
        await mkdir(home, { recursive: true });
        await writeFile(path.join(home, ".env"), "MAX_STEPS=88\n", "utf8");
        const payload = await buildStructuredConfigPayload({
            ...createTestAgentConfig(workspace),
            maxSteps: 88,
        }, home);
        const maxSteps = payload.entries.find((entry) => entry.key === "maxSteps");
        assert.equal(maxSteps?.persistedValue, 88);
        assert.equal(maxSteps?.envValue, null);
        assert.equal(maxSteps?.envSource, null);
        assert.equal(maxSteps?.envSourcePath, null);
        assert.equal(maxSteps?.overriddenByEnv, false);
    });
});
test("applyPersistedConfigUpdates writes ~/.minicode/.env and removes keys when unset", async () => {
    const home = await mkdtemp(path.join(os.tmpdir(), "minicode-editable-config-"));
    tempDirs.push(home);
    const result = await applyPersistedConfigUpdates({
        minicodeHome: home,
        updates: {
            keepRecentMessages: 18,
            enableFileReadDedup: false,
        },
    });
    assert.equal(result.path, getGlobalConfigPath(home));
    assert.deepEqual(result.saved, [
        { key: "keepRecentMessages", value: 18 },
        { key: "enableFileReadDedup", value: false },
    ]);
    const envPath = path.join(home, ".env");
    let persisted = await readFile(envPath, "utf8");
    assert.match(persisted, /^KEEP_RECENT_MESSAGES=18$/m);
    assert.match(persisted, /^ENABLE_FILE_READ_DEDUP=false$/m);
    await applyPersistedConfigUpdates({
        minicodeHome: home,
        updates: {
            keepRecentMessages: null,
            enableFileReadDedup: null,
        },
    });
    persisted = await readFile(envPath, "utf8");
    assert.doesNotMatch(persisted, /^KEEP_RECENT_MESSAGES=/m);
    assert.doesNotMatch(persisted, /^ENABLE_FILE_READ_DEDUP=/m);
});
