"use strict";
/**
 * CLIProxy Variant Settings File Manager
 *
 * Handles creation of settings.json files for CLIProxy variants.
 * These files contain environment variables for Claude CLI integration.
 */
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.updateSettingsProviderAndModel = exports.updateSettingsModel = exports.deleteSettingsFile = exports.getCompositeRelativeSettingsPath = exports.createCompositeSettingsFile = exports.createSettingsFileUnified = exports.createSettingsFile = exports.getRelativeSettingsPath = exports.getSettingsFileName = exports.getSettingsFilePath = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const helpers_1 = require("../../utils/helpers");
const config_generator_1 = require("../config/config-generator");
const websearch_manager_1 = require("../../utils/websearch-manager");
const image_analysis_1 = require("../../utils/image-analysis");
const image_analyzer_profile_hook_injector_1 = require("../../utils/hooks/image-analyzer-profile-hook-injector");
const hooks_1 = require("../../utils/hooks");
const auth_token_manager_1 = require("../auth/auth-token-manager");
const ui_1 = require("../../utils/ui");
const model_id_normalizer_1 = require("../ai-providers/model-id-normalizer");
const config_loader_facade_1 = require("../../config/config-loader-facade");
function canonicalizeModelForProvider(provider, model) {
    if (!provider)
        return model;
    return (0, model_id_normalizer_1.normalizeModelIdForProvider)(model, provider);
}
/**
 * Build settings env object for a variant
 */
function buildSettingsEnv(provider, model, port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
    const baseEnv = (0, config_generator_1.getClaudeEnvVars)(provider, port);
    const normalizedModel = canonicalizeModelForProvider(provider, model);
    const defaultModel = normalizedModel;
    const opusModel = normalizedModel;
    const sonnetModel = normalizedModel;
    const haikuModel = canonicalizeModelForProvider(provider, baseEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL || model);
    return {
        ANTHROPIC_BASE_URL: baseEnv.ANTHROPIC_BASE_URL || '',
        ANTHROPIC_AUTH_TOKEN: baseEnv.ANTHROPIC_AUTH_TOKEN || '',
        ANTHROPIC_MODEL: defaultModel,
        ANTHROPIC_DEFAULT_OPUS_MODEL: opusModel,
        ANTHROPIC_DEFAULT_SONNET_MODEL: sonnetModel,
        ANTHROPIC_DEFAULT_HAIKU_MODEL: haikuModel,
    };
}
/**
 * Ensure directory exists
 */
function ensureDir(dir) {
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
}
/**
 * Write settings file atomically using temp file + rename.
 * The renameSync is atomic on POSIX systems, preventing partial writes on crash.
 */
function writeSettings(filePath, settings) {
    const tempPath = `${filePath}.tmp.${process.pid}`;
    fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
    fs.renameSync(tempPath, filePath);
}
function rollbackSettingsFile(filePath, previousContent, existedBefore) {
    if (existedBefore && previousContent !== null) {
        fs.writeFileSync(filePath, previousContent, 'utf8');
        return;
    }
    if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
    }
}
/**
 * Get settings file path for a variant
 */
function getSettingsFilePath(provider, name) {
    const ccsDir = (0, config_loader_facade_1.getCcsDir)();
    return path.join(ccsDir, `${provider}-${name}.settings.json`);
}
exports.getSettingsFilePath = getSettingsFilePath;
/**
 * Get settings file name (without path)
 */
function getSettingsFileName(provider, name) {
    return `${provider}-${name}.settings.json`;
}
exports.getSettingsFileName = getSettingsFileName;
/**
 * Get relative settings path with ~ prefix
 */
function getRelativeSettingsPath(provider, name) {
    return `~/.ccs/${getSettingsFileName(provider, name)}`;
}
exports.getRelativeSettingsPath = getRelativeSettingsPath;
/**
 * Create settings.json file for CLIProxy variant (legacy mode)
 */
function createSettingsFile(name, provider, model, port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
    const ccsDir = (0, config_loader_facade_1.getCcsDir)();
    const settingsPath = getSettingsFilePath(provider, name);
    const settings = {
        env: buildSettingsEnv(provider, model, port),
    };
    const settingsExisted = fs.existsSync(settingsPath);
    const previousSettingsContent = settingsExisted ? fs.readFileSync(settingsPath, 'utf8') : null;
    ensureDir(ccsDir);
    writeSettings(settingsPath, settings);
    try {
        (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
        const imageAnalysisMcpReady = (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
        if (imageAnalysisMcpReady) {
            (0, image_analyzer_profile_hook_injector_1.removeImageAnalysisProfileHook)(`${provider}-${name}`, settingsPath);
        }
        else {
            const imageAnalysisFallbackHookReady = (0, hooks_1.prepareImageAnalysisFallbackHook)();
            (0, image_analyzer_profile_hook_injector_1.ensureProfileHooks)({
                profileName: `${provider}-${name}`,
                profileType: 'cliproxy',
                cliproxyProvider: provider,
                settingsPath,
                sharedHookInstalled: imageAnalysisFallbackHookReady,
            });
        }
    }
    catch (error) {
        rollbackSettingsFile(settingsPath, previousSettingsContent, settingsExisted);
        throw error;
    }
    return settingsPath;
}
exports.createSettingsFile = createSettingsFile;
/**
 * Create settings.json file for CLIProxy variant (unified mode)
 */
function createSettingsFileUnified(name, provider, model, port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
    const ccsDir = (0, config_loader_facade_1.getCcsDir)(); // Use centralized function for CCS_HOME support
    const settingsPath = path.join(ccsDir, getSettingsFileName(provider, name));
    const settings = {
        env: buildSettingsEnv(provider, model, port),
    };
    const settingsExisted = fs.existsSync(settingsPath);
    const previousSettingsContent = settingsExisted ? fs.readFileSync(settingsPath, 'utf8') : null;
    ensureDir(ccsDir);
    writeSettings(settingsPath, settings);
    try {
        (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
        const imageAnalysisMcpReady = (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
        if (imageAnalysisMcpReady) {
            (0, image_analyzer_profile_hook_injector_1.removeImageAnalysisProfileHook)(`${provider}-${name}`, settingsPath);
        }
        else {
            const imageAnalysisFallbackHookReady = (0, hooks_1.prepareImageAnalysisFallbackHook)();
            (0, image_analyzer_profile_hook_injector_1.ensureProfileHooks)({
                profileName: `${provider}-${name}`,
                profileType: 'cliproxy',
                cliproxyProvider: provider,
                settingsPath,
                sharedHookInstalled: imageAnalysisFallbackHookReady,
            });
        }
    }
    catch (error) {
        rollbackSettingsFile(settingsPath, previousSettingsContent, settingsExisted);
        throw error;
    }
    return settingsPath;
}
exports.createSettingsFileUnified = createSettingsFileUnified;
/**
 * Build settings env object for a composite variant.
 * Uses root URL (no /api/provider/ path) for model-based routing.
 */
function buildCompositeSettingsEnv(tiers, defaultTier, port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
    const defaultModel = tiers[defaultTier].model;
    return {
        // Root URL — CLIProxyAPI routes based on model name, no provider prefix
        ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}`,
        ANTHROPIC_AUTH_TOKEN: (0, auth_token_manager_1.getEffectiveApiKey)(),
        ANTHROPIC_MODEL: defaultModel,
        ANTHROPIC_DEFAULT_OPUS_MODEL: tiers.opus.model,
        ANTHROPIC_DEFAULT_SONNET_MODEL: tiers.sonnet.model,
        ANTHROPIC_DEFAULT_HAIKU_MODEL: tiers.haiku.model,
    };
}
/**
 * Create settings.json file for a composite variant.
 */
function createCompositeSettingsFile(name, tiers, defaultTier, port = config_generator_1.CLIPROXY_DEFAULT_PORT, settingsPathOverride) {
    const ccsDir = (0, config_loader_facade_1.getCcsDir)();
    const defaultSettingsPath = path.join(ccsDir, `composite-${name}.settings.json`);
    const settingsPath = settingsPathOverride
        ? (() => {
            const expanded = (0, helpers_1.expandPath)(settingsPathOverride);
            return path.isAbsolute(expanded) ? expanded : path.join(ccsDir, expanded);
        })()
        : defaultSettingsPath;
    const settingsDir = path.dirname(settingsPath);
    const coreEnv = buildCompositeSettingsEnv(tiers, defaultTier, port);
    let settings = { env: coreEnv };
    // Preserve non-core env vars and non-env fields (hooks/presets/etc.) when regenerating.
    if (fs.existsSync(settingsPath)) {
        try {
            const content = fs.readFileSync(settingsPath, 'utf-8');
            const parsed = JSON.parse(content);
            if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
                const existingEnv = parsed.env && typeof parsed.env === 'object' && !Array.isArray(parsed.env)
                    ? parsed.env
                    : {};
                const { ANTHROPIC_BASE_URL: _baseUrl, ANTHROPIC_AUTH_TOKEN: _authToken, ANTHROPIC_MODEL: _model, ANTHROPIC_DEFAULT_OPUS_MODEL: _opus, ANTHROPIC_DEFAULT_SONNET_MODEL: _sonnet, ANTHROPIC_DEFAULT_HAIKU_MODEL: _haiku, ...extraEnv } = existingEnv;
                settings = {
                    ...parsed,
                    env: {
                        ...extraEnv,
                        ...coreEnv,
                    },
                };
            }
        }
        catch {
            // Invalid JSON — overwrite with a clean settings object.
        }
    }
    const settingsExisted = fs.existsSync(settingsPath);
    const previousSettingsContent = settingsExisted ? fs.readFileSync(settingsPath, 'utf8') : null;
    ensureDir(settingsDir);
    writeSettings(settingsPath, settings);
    if (path.resolve(settingsPath) === path.resolve(defaultSettingsPath)) {
        try {
            (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
            const imageAnalysisMcpReady = (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
            if (imageAnalysisMcpReady) {
                (0, image_analyzer_profile_hook_injector_1.removeImageAnalysisProfileHook)(`composite-${name}`, settingsPath);
            }
            else {
                const imageAnalysisFallbackHookReady = (0, hooks_1.prepareImageAnalysisFallbackHook)();
                (0, image_analyzer_profile_hook_injector_1.ensureProfileHooks)({
                    profileName: `composite-${name}`,
                    profileType: 'cliproxy',
                    cliproxyProvider: tiers[defaultTier].provider,
                    isComposite: true,
                    settingsPath,
                    sharedHookInstalled: imageAnalysisFallbackHookReady,
                });
            }
        }
        catch (error) {
            rollbackSettingsFile(settingsPath, previousSettingsContent, settingsExisted);
            throw error;
        }
    }
    return settingsPath;
}
exports.createCompositeSettingsFile = createCompositeSettingsFile;
/**
 * Get relative settings path for a composite variant
 */
function getCompositeRelativeSettingsPath(name) {
    return `~/.ccs/composite-${name}.settings.json`;
}
exports.getCompositeRelativeSettingsPath = getCompositeRelativeSettingsPath;
/**
 * Delete settings file if it exists.
 * Uses expandPath() for cross-platform path handling.
 */
function deleteSettingsFile(settingsPath) {
    const resolvedPath = (0, helpers_1.expandPath)(settingsPath);
    if (fs.existsSync(resolvedPath)) {
        fs.unlinkSync(resolvedPath);
        return true;
    }
    return false;
}
exports.deleteSettingsFile = deleteSettingsFile;
/**
 * Update model in an existing settings file
 */
function updateSettingsModel(settingsPath, model, provider, options) {
    const fileName = path.basename(settingsPath);
    if (fileName.startsWith('composite-')) {
        console.log((0, ui_1.warn)('Cannot update model for composite variant. Edit config.yaml tiers directly.'));
        return;
    }
    const resolvedPath = settingsPath.replace(/^~/, os.homedir());
    if (!fs.existsSync(resolvedPath)) {
        return;
    }
    try {
        const content = fs.readFileSync(resolvedPath, 'utf8');
        const settings = JSON.parse(content);
        if (model) {
            settings.env = settings.env || {};
            const normalizedModel = canonicalizeModelForProvider(provider, model);
            settings.env.ANTHROPIC_MODEL = normalizedModel;
            settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = normalizedModel;
            settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = normalizedModel;
            if (provider === 'codex' && settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
                const normalizedHaikuModel = canonicalizeModelForProvider(provider, settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL);
                settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = options?.rewriteHaikuModel
                    ? options.rewriteHaikuModel(normalizedHaikuModel)
                    : normalizedHaikuModel;
            }
        }
        else {
            // Clear model settings to use defaults
            delete settings.env.ANTHROPIC_MODEL;
        }
        const tempPath = `${resolvedPath}.tmp.${process.pid}`;
        fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
        fs.renameSync(tempPath, resolvedPath);
    }
    catch {
        // Ignore errors - settings file may be invalid
    }
}
exports.updateSettingsModel = updateSettingsModel;
/**
 * Update provider + model core env vars in an existing single-provider settings file.
 * Preserves non-core env vars and top-level settings keys (hooks, presets, etc.).
 */
function updateSettingsProviderAndModel(settingsPath, provider, model, port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
    const resolvedPath = (0, helpers_1.expandPath)(settingsPath);
    const fileName = path.basename(resolvedPath);
    if (fileName.startsWith('composite-')) {
        console.log((0, ui_1.warn)('Cannot update provider/model for composite variant. Edit config.yaml tiers directly.'));
        return;
    }
    const coreEnv = buildSettingsEnv(provider, model, port);
    let settings = { env: coreEnv };
    if (fs.existsSync(resolvedPath)) {
        try {
            const content = fs.readFileSync(resolvedPath, 'utf8');
            const parsed = JSON.parse(content);
            if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
                const existingEnv = parsed.env && typeof parsed.env === 'object' && !Array.isArray(parsed.env)
                    ? parsed.env
                    : {};
                const { ANTHROPIC_BASE_URL: _baseUrl, ANTHROPIC_AUTH_TOKEN: _authToken, ANTHROPIC_MODEL: _model, ANTHROPIC_DEFAULT_OPUS_MODEL: _opus, ANTHROPIC_DEFAULT_SONNET_MODEL: _sonnet, ANTHROPIC_DEFAULT_HAIKU_MODEL: _haiku, ...extraEnv } = existingEnv;
                settings = {
                    ...parsed,
                    env: {
                        ...extraEnv,
                        ...coreEnv,
                    },
                };
            }
        }
        catch {
            // Keep default and overwrite malformed file.
        }
    }
    ensureDir(path.dirname(resolvedPath));
    writeSettings(resolvedPath, settings);
}
exports.updateSettingsProviderAndModel = updateSettingsProviderAndModel;
//# sourceMappingURL=variant-settings.js.map