"use strict";
/**
 * WebSearch Hook Configuration
 *
 * Manages hook configuration in Claude settings.json.
 *
 * @module utils/websearch/hook-config
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeHookConfig = exports.ensureHookConfig = exports.getWebSearchHookConfig = exports.getHookPath = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ui_1 = require("../ui");
const config_manager_1 = require("../config-manager");
const claude_config_path_1 = require("../claude-config-path");
const hook_utils_1 = require("./hook-utils");
const config_loader_facade_1 = require("../../config/config-loader-facade");
// Hook file name
const WEBSEARCH_HOOK = 'websearch-transformer.cjs';
// Buffer time added to max provider timeout for hook timeout (seconds)
const HOOK_TIMEOUT_BUFFER = 30;
// Minimum hook timeout in seconds (fallback if no providers configured)
const MIN_HOOK_TIMEOUT = 60;
/**
 * Get path to WebSearch hook
 */
function getHookPath() {
    return path.join((0, config_manager_1.getCcsHooksDir)(), WEBSEARCH_HOOK);
}
exports.getHookPath = getHookPath;
/**
 * Get WebSearch hook configuration for settings.json
 * Timeout is computed from max provider timeout in config.yaml + buffer
 */
function getWebSearchHookConfig() {
    const hookPath = getHookPath();
    const wsConfig = (0, config_loader_facade_1.getWebSearchConfig)();
    // Compute max timeout from enabled providers
    const timeouts = [];
    if (wsConfig.providers?.gemini?.enabled && wsConfig.providers.gemini.timeout) {
        timeouts.push(wsConfig.providers.gemini.timeout);
    }
    if (wsConfig.providers?.opencode?.enabled && wsConfig.providers.opencode.timeout) {
        timeouts.push(wsConfig.providers.opencode.timeout);
    }
    if (wsConfig.providers?.grok?.enabled && wsConfig.providers.grok.timeout) {
        timeouts.push(wsConfig.providers.grok.timeout);
    }
    // Hook timeout = max provider timeout + buffer (or minimum if none configured)
    const maxProviderTimeout = timeouts.length > 0 ? Math.max(...timeouts) : MIN_HOOK_TIMEOUT;
    const hookTimeout = maxProviderTimeout + HOOK_TIMEOUT_BUFFER;
    return {
        PreToolUse: [
            {
                matcher: 'WebSearch',
                hooks: [
                    {
                        type: 'command',
                        command: `node "${hookPath}"`,
                        timeout: hookTimeout,
                    },
                ],
            },
        ],
    };
}
exports.getWebSearchHookConfig = getWebSearchHookConfig;
/**
 * Ensure WebSearch hook is configured in ~/.claude/settings.json
 */
function ensureHookConfig() {
    try {
        const wsConfig = (0, config_loader_facade_1.getWebSearchConfig)();
        if (!wsConfig.enabled) {
            return false;
        }
        // Read existing settings or start fresh
        let settings = {};
        if (fs.existsSync((0, claude_config_path_1.getClaudeSettingsPath)())) {
            try {
                const content = fs.readFileSync((0, claude_config_path_1.getClaudeSettingsPath)(), 'utf8');
                settings = JSON.parse(content);
            }
            catch {
                if (process.env.CCS_DEBUG) {
                    console.error((0, ui_1.warn)('Malformed settings.json - will merge carefully'));
                }
            }
        }
        // Check if WebSearch hook already configured
        const hooks = settings.hooks;
        const expectedHookPath = getHookPath();
        const expectedCommand = `node "${expectedHookPath}"`;
        if (hooks?.PreToolUse) {
            const webSearchHookIndex = hooks.PreToolUse.findIndex((h) => {
                const hook = h;
                if (hook.matcher !== 'WebSearch')
                    return false;
                const hookArray = hook.hooks;
                const command = hookArray?.[0]?.command;
                if (typeof command !== 'string')
                    return false;
                const normalized = command
                    .replace(/\\/g, '/') // Windows backslashes
                    .replace(/\/+/g, '/'); // Collapse multiple slashes
                return normalized.includes('.ccs/hooks/websearch-transformer');
            });
            if (webSearchHookIndex !== -1) {
                // Hook exists - first clean up any duplicates
                // INVARIANT: webSearchHookIndex remains valid after deduplication because:
                // - findIndex() returns the FIRST matching CCS hook
                // - deduplicateCcsHooks() keeps the FIRST CCS hook and removes subsequent duplicates
                // This means the index always points to the preserved hook.
                const hadDuplicates = (0, hook_utils_1.deduplicateCcsHooks)(settings);
                // Then check if it needs updating
                const existingHook = hooks.PreToolUse[webSearchHookIndex];
                const existingHooks = existingHook.hooks;
                const currentHookConfig = getWebSearchHookConfig();
                const expectedHooks = currentHookConfig.PreToolUse[0]
                    .hooks;
                const expectedTimeout = expectedHooks[0].timeout;
                let needsUpdate = false;
                if (existingHooks?.[0]?.command !== expectedCommand) {
                    existingHooks[0].command = expectedCommand;
                    needsUpdate = true;
                }
                if (existingHooks?.[0]?.timeout !== expectedTimeout) {
                    existingHooks[0].timeout = expectedTimeout;
                    needsUpdate = true;
                }
                // Combine into single write if either changed
                if (hadDuplicates || needsUpdate) {
                    fs.writeFileSync((0, claude_config_path_1.getClaudeSettingsPath)(), JSON.stringify(settings, null, 2), 'utf8');
                    if (process.env.CCS_DEBUG) {
                        if (hadDuplicates)
                            console.error((0, ui_1.info)('Removed duplicate WebSearch hooks from settings.json'));
                        if (needsUpdate)
                            console.error((0, ui_1.info)('Updated WebSearch hook config in settings.json'));
                    }
                }
                return true;
            }
        }
        // Get hook config
        const hookConfig = getWebSearchHookConfig();
        // Merge hook config into settings
        if (!settings.hooks) {
            settings.hooks = {};
        }
        const settingsHooks = settings.hooks;
        if (!settingsHooks.PreToolUse) {
            settingsHooks.PreToolUse = [];
        }
        // Remove any existing CCS hooks first to prevent duplicates
        settingsHooks.PreToolUse = settingsHooks.PreToolUse.filter((h) => {
            const hook = h;
            return !(0, hook_utils_1.isCcsWebSearchHook)(hook);
        });
        // Add our hook config
        const preToolUseHooks = hookConfig.PreToolUse;
        settingsHooks.PreToolUse.push(...preToolUseHooks);
        // Ensure ~/.claude directory exists
        const claudeDir = path.dirname((0, claude_config_path_1.getClaudeSettingsPath)());
        if (!fs.existsSync(claudeDir)) {
            fs.mkdirSync(claudeDir, { recursive: true, mode: 0o700 });
        }
        // Write updated settings
        fs.writeFileSync((0, claude_config_path_1.getClaudeSettingsPath)(), JSON.stringify(settings, null, 2), 'utf8');
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.info)('Added WebSearch hook to settings.json'));
        }
        return true;
    }
    catch (error) {
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.warn)(`Failed to configure WebSearch hook: ${error.message}`));
        }
        return false;
    }
}
exports.ensureHookConfig = ensureHookConfig;
/**
 * Remove CCS WebSearch hook from ~/.claude/settings.json
 * Only removes hooks matching: matcher='WebSearch' AND command contains '.ccs/hooks/websearch-transformer'
 * Preserves user-defined WebSearch hooks
 */
function removeHookConfig() {
    try {
        if (!fs.existsSync((0, claude_config_path_1.getClaudeSettingsPath)())) {
            return true; // Nothing to remove
        }
        const content = fs.readFileSync((0, claude_config_path_1.getClaudeSettingsPath)(), 'utf8');
        let settings;
        try {
            settings = JSON.parse(content);
        }
        catch {
            return false; // Malformed JSON, don't touch
        }
        const hooks = settings.hooks;
        if (!hooks?.PreToolUse) {
            return true; // No hooks to remove
        }
        const originalLength = hooks.PreToolUse.length;
        hooks.PreToolUse = hooks.PreToolUse.filter((h) => {
            const hook = h;
            if (hook.matcher !== 'WebSearch')
                return true; // Keep non-WebSearch hooks
            const hookArray = hook.hooks;
            if (!hookArray?.[0]?.command)
                return true; // Keep malformed entries
            const command = hookArray[0].command;
            // Normalize path separators for cross-platform matching (Windows uses backslashes)
            const normalizedCommand = command
                .replace(/\\/g, '/') // Windows backslashes
                .replace(/\/+/g, '/'); // Collapse multiple slashes
            return !normalizedCommand.includes('.ccs/hooks/websearch-transformer'); // Remove if CCS hook
        });
        if (hooks.PreToolUse.length === originalLength) {
            return true; // Nothing changed
        }
        // Clean up empty hooks object
        if (hooks.PreToolUse.length === 0) {
            delete hooks.PreToolUse;
        }
        if (Object.keys(hooks).length === 0) {
            delete settings.hooks;
        }
        fs.writeFileSync((0, claude_config_path_1.getClaudeSettingsPath)(), JSON.stringify(settings, null, 2), 'utf8');
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.info)('Removed WebSearch hook from settings.json'));
        }
        return true;
    }
    catch (error) {
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.warn)(`Failed to remove hook config: ${error.message}`));
        }
        return false;
    }
}
exports.removeHookConfig = removeHookConfig;
//# sourceMappingURL=hook-config.js.map