"use strict";
/**
 * Profile Hook Injector
 *
 * Injects the legacy WebSearch compatibility hook into per-profile settings files.
 * The first-class runtime now uses the CCS-managed MCP server; these hooks remain
 * for compatibility and migration safety only.
 *
 * @module utils/websearch/profile-hook-injector
 */
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.ensureProfileHooksOrThrow = exports.ensureProfileHooks = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ui_1 = require("../ui");
const hook_config_1 = require("./hook-config");
const hook_config_2 = require("./hook-config");
const config_manager_1 = require("../config-manager");
const hook_utils_1 = require("./hook-utils");
const hook_installer_1 = require("./hook-installer");
const config_loader_facade_1 = require("../../config/config-loader-facade");
// Valid profile name pattern (alphanumeric, dash, underscore only)
const VALID_PROFILE_NAME = /^[a-zA-Z0-9_-]+$/;
function hasUsableHookBinary() {
    try {
        const hookPath = (0, hook_config_1.getHookPath)();
        const stat = fs.statSync(hookPath);
        if (!stat.isFile()) {
            return false;
        }
        fs.accessSync(hookPath, fs.constants.R_OK);
        return true;
    }
    catch {
        return false;
    }
}
/**
 * Check if CCS WebSearch hook exists in settings
 */
function hasCcsHook(settings) {
    const hooks = settings.hooks;
    if (!hooks?.PreToolUse)
        return false;
    return hooks.PreToolUse.some((h) => {
        return (0, hook_utils_1.isCcsWebSearchHook)(h);
    });
}
/**
 * Migrate CCS hook from global settings to profile settings (one-time)
 */
function migrateGlobalHook() {
    const markerPath = (0, hook_installer_1.getMigrationMarkerPath)();
    if (fs.existsSync(markerPath)) {
        return; // Already migrated
    }
    try {
        const removed = (0, hook_config_2.removeHookConfig)();
        if (removed && process.env.CCS_DEBUG) {
            console.error((0, ui_1.info)('Migrated WebSearch hook from global settings'));
        }
        // Ensure CCS dir exists before creating marker
        const ccsDir = (0, config_manager_1.getCcsDir)();
        if (!fs.existsSync(ccsDir)) {
            fs.mkdirSync(ccsDir, { recursive: true, mode: 0o700 });
        }
        // Create marker file atomically (wx = fail if exists, prevents race condition)
        fs.writeFileSync(markerPath, new Date().toISOString(), { encoding: 'utf8', flag: 'wx' });
    }
    catch (error) {
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.warn)(`Migration failed: ${error.message}`));
        }
    }
}
/**
 * Ensure the legacy WebSearch compatibility hook is configured in a profile's
 * settings file when that path is still needed.
 *
 * @param profileName - Name of the profile (e.g., 'agy', 'gemini', 'glm')
 * @returns true if hook is configured (existing or newly added)
 */
function ensureProfileHooks(profileName) {
    try {
        // Validate profile name to prevent path traversal
        if (!VALID_PROFILE_NAME.test(profileName)) {
            if (process.env.CCS_DEBUG) {
                console.error((0, ui_1.warn)(`Invalid profile name: ${profileName}`));
            }
            return false;
        }
        const wsConfig = (0, config_loader_facade_1.getWebSearchConfig)();
        // Skip if WebSearch is disabled
        if (!wsConfig.enabled) {
            return false;
        }
        // Get CCS directory (respects CCS_HOME for test isolation)
        const ccsDir = (0, config_manager_1.getCcsDir)();
        const settingsPath = path.join(ccsDir, `${profileName}.settings.json`);
        // Read existing settings or create empty
        let settings = {};
        if (fs.existsSync(settingsPath)) {
            try {
                const content = fs.readFileSync(settingsPath, 'utf8');
                settings = JSON.parse(content);
            }
            catch (parseError) {
                if (process.env.CCS_DEBUG) {
                    console.error((0, ui_1.warn)(`Malformed ${profileName}.settings.json: ${parseError.message}`));
                }
                // Never overwrite malformed settings files; avoid destructive data loss.
                return false;
            }
        }
        // Keep the injected command target valid for all profile types, not just CLIProxy.
        // The installer already skips byte-identical copies, so we can always attempt a refresh
        // without rewriting unchanged hooks. Re-check existence after a failed install to tolerate
        // concurrent first-run installs that may have completed in another process.
        if (!(0, hook_installer_1.installWebSearchHook)() && !hasUsableHookBinary()) {
            if (process.env.CCS_DEBUG) {
                console.error((0, ui_1.warn)('WebSearch hook binary is missing and could not be installed'));
            }
            return false;
        }
        // One-time migration from global settings
        migrateGlobalHook();
        // Ensure CCS dir exists before writing settings updates.
        if (!fs.existsSync(ccsDir)) {
            fs.mkdirSync(ccsDir, { recursive: true, mode: 0o700 });
        }
        // Check if CCS hook already present
        if (hasCcsHook(settings)) {
            // Clean up any duplicates that may have accumulated (Windows path bug fix)
            const hadDuplicates = (0, hook_utils_1.deduplicateCcsHooks)(settings);
            if (hadDuplicates) {
                // Re-read file to compare with modified settings (deduplicateCcsHooks mutates in-place)
                const newContent = JSON.stringify(settings, null, 2);
                const existingContent = fs.readFileSync(settingsPath, 'utf8');
                // Only write if content actually changed
                if (newContent !== existingContent) {
                    fs.writeFileSync(settingsPath, newContent, 'utf8');
                    if (process.env.CCS_DEBUG) {
                        console.error((0, ui_1.info)(`Removed duplicate WebSearch hooks from ${profileName}.settings.json`));
                    }
                }
            }
            // Update timeout if needed
            return updateHookTimeoutIfNeeded(settings, settingsPath);
        }
        // Get hook config
        const hookConfig = (0, hook_config_1.getWebSearchHookConfig)();
        // Ensure hooks structure exists
        if (!settings.hooks) {
            settings.hooks = {};
        }
        const settingsHooks = settings.hooks;
        if (!settingsHooks.PreToolUse) {
            settingsHooks.PreToolUse = [];
        }
        // Add CCS hook
        const preToolUseHooks = hookConfig.PreToolUse;
        settingsHooks.PreToolUse.push(...preToolUseHooks);
        // Write updated settings
        fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.info)(`Added WebSearch hook to ${profileName}.settings.json`));
        }
        return true;
    }
    catch (error) {
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.warn)(`Failed to inject hook: ${error.message}`));
        }
        return false;
    }
}
exports.ensureProfileHooks = ensureProfileHooks;
function ensureProfileHooksOrThrow(profileName) {
    const wsConfig = (0, config_loader_facade_1.getWebSearchConfig)();
    if (!wsConfig.enabled) {
        return;
    }
    if (!ensureProfileHooks(profileName)) {
        throw new Error(`WebSearch is enabled, but CCS could not prepare the profile hook for "${profileName}".`);
    }
}
exports.ensureProfileHooksOrThrow = ensureProfileHooksOrThrow;
/**
 * Update hook timeout if it differs from current config
 */
function updateHookTimeoutIfNeeded(settings, settingsPath) {
    try {
        const hooks = settings.hooks;
        const hookConfig = (0, hook_config_1.getWebSearchHookConfig)();
        const expectedHookPath = (0, hook_config_1.getHookPath)();
        const expectedCommand = `node "${expectedHookPath}"`;
        const expectedHooks = hookConfig.PreToolUse[0]
            .hooks;
        const expectedTimeout = expectedHooks[0].timeout;
        let needsUpdate = false;
        for (const h of hooks.PreToolUse) {
            const hook = h;
            if (hook.matcher !== 'WebSearch')
                continue;
            const hookArray = hook.hooks;
            if (!hookArray?.[0]?.command)
                continue;
            const command = hookArray[0].command;
            if (typeof command !== 'string')
                continue;
            // Normalize path separators for cross-platform matching (Windows uses backslashes)
            const normalizedCommand = command
                .replace(/\\/g, '/') // Windows backslashes
                .replace(/\/+/g, '/'); // Collapse multiple slashes
            if (!normalizedCommand.includes('.ccs/hooks/websearch-transformer'))
                continue;
            // Found CCS hook - check if needs update
            if (hookArray[0].command !== expectedCommand) {
                hookArray[0].command = expectedCommand;
                needsUpdate = true;
            }
            if (hookArray[0].timeout !== expectedTimeout) {
                hookArray[0].timeout = expectedTimeout;
                needsUpdate = true;
            }
        }
        if (needsUpdate) {
            fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
            if (process.env.CCS_DEBUG) {
                console.error((0, ui_1.info)('Updated WebSearch hook timeout in profile settings'));
            }
        }
        return true;
    }
    catch (error) {
        if (process.env.CCS_DEBUG) {
            console.error((0, ui_1.warn)(`updateHookTimeoutIfNeeded failed: ${error.message}`));
        }
        return false;
    }
}
//# sourceMappingURL=profile-hook-injector.js.map