"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareHookSettings = prepareHookSettings;
exports.cleanupHookSettings = cleanupHookSettings;
const promises_1 = require("node:fs/promises");
const node_os_1 = require("node:os");
const node_path_1 = __importDefault(require("node:path"));
const paths_1 = require("../server/paths");
const hook_bridge_path_1 = require("./hook-bridge-path");
const HOOK_EVENTS = [
    "PreToolUse",
    "PostToolUse",
    "Stop",
    "StopFailure",
    "UserPromptSubmit",
    "UserPromptExpansion",
    "SubagentStart",
    "SubagentStop",
    "Notification",
    "PermissionRequest",
    "PreCompact",
    "PostCompact",
];
const PERMISSION_HOOK_TIMEOUT_SEC = 86400;
/**
 * Build and write the per-session claude settings file. The file lives in
 * `~/.cache/cockpit/hook-settings/<sessionId>.json` (or `$TMPDIR` if HOME
 * is not writable). Call `cleanupHookSettings` on session destroy.
 */
async function prepareHookSettings(opts) {
    const bridge = (0, hook_bridge_path_1.resolveHookBridgePath)();
    const base = await loadUserSettings();
    const hooks = buildHooksBlock(bridge);
    const existingHooks = (base.hooks ?? {});
    for (const [event, entries] of Object.entries(existingHooks)) {
        if (Array.isArray(entries) && entries.length > 0) {
            if (hooks[event]) {
                hooks[event] = [...entries, ...hooks[event]];
            }
        }
    }
    const baseAllow = Array.isArray(base.permissions?.allow)
        ? base.permissions.allow
        : [];
    const baseDeny = Array.isArray(base.permissions?.deny)
        ? base.permissions.deny
        : [];
    const settings = {
        ...base,
        hooks,
        permissions: {
            ...(base.permissions ?? {}),
            allow: [...baseAllow, ...(opts.allowList ?? [])],
            deny: [...baseDeny, ...(opts.denyList ?? [])],
        },
        // cockpit drives the CLI programmatically and owns the bypass-mode UX
        // itself (flipping bypass on is a deliberate cockpit UI action). The CLI's
        // interactive "WARNING: Bypass Permissions mode" dialog has nowhere to go
        // when there's no human at the TUI, so suppress it here.
        skipDangerousModePermissionPrompt: true,
    };
    const dir = await resolveSettingsDir();
    const settingsPath = node_path_1.default.join(dir, `${opts.sessionId}.json`);
    await (0, promises_1.writeFile)(settingsPath, JSON.stringify(settings, null, 2), { mode: 0o600 });
    return {
        settingsPath,
        env: {
            COCKPIT_HOOK_URL: opts.hookUrl,
            COCKPIT_HOOK_TOKEN: opts.hookToken,
            COCKPIT_SESSION_ID: opts.sessionId,
        },
    };
}
async function cleanupHookSettings(sessionId) {
    const dir = await resolveSettingsDir();
    const settingsPath = node_path_1.default.join(dir, `${sessionId}.json`);
    await (0, promises_1.rm)(settingsPath, { force: true });
}
function buildHooksBlock(bridgePath) {
    const block = {};
    for (const event of HOOK_EVENTS) {
        const cmd = {
            type: "command",
            command: `node ${shellQuote(bridgePath)} ${event}`,
        };
        if (event === "PermissionRequest") {
            cmd.timeout = PERMISSION_HOOK_TIMEOUT_SEC;
        }
        block[event] = [{ matcher: "", hooks: [cmd] }];
    }
    return block;
}
function shellQuote(p) {
    if (!/[\s"'\\$`]/.test(p))
        return p;
    return `'${p.replace(/'/g, "'\\''")}'`;
}
function userSettingsPaths() {
    return [node_path_1.default.join((0, paths_1.getClaudeDir)(), "settings.json"), node_path_1.default.join((0, paths_1.getClaudeDir)(), "settings.local.json")];
}
async function loadUserSettings() {
    let merged = {};
    for (const p of userSettingsPaths()) {
        try {
            const raw = await (0, promises_1.readFile)(p, "utf-8");
            const parsed = JSON.parse(raw);
            if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
                merged = deepMerge(merged, parsed);
            }
        }
        catch {
            // file missing or malformed
        }
    }
    return merged;
}
function deepMerge(target, source) {
    const result = { ...target };
    for (const key of Object.keys(source)) {
        const tVal = target[key];
        const sVal = source[key];
        if (isPlainObject(tVal) && isPlainObject(sVal)) {
            result[key] = deepMerge(tVal, sVal);
        }
        else {
            result[key] = sVal;
        }
    }
    return result;
}
function isPlainObject(v) {
    return v !== null && typeof v === "object" && !Array.isArray(v);
}
let settingsDirCache = null;
async function resolveSettingsDir() {
    if (settingsDirCache)
        return settingsDirCache;
    const primary = node_path_1.default.join((0, paths_1.getCockpitCacheDir)(), "hook-settings");
    try {
        await (0, promises_1.mkdir)(primary, { recursive: true });
        settingsDirCache = primary;
        return primary;
    }
    catch {
        const fallback = node_path_1.default.join((0, node_os_1.tmpdir)(), "cockpit-hook-settings");
        await (0, promises_1.mkdir)(fallback, { recursive: true });
        settingsDirCache = fallback;
        return fallback;
    }
}
