"use strict";
/**
 * Environment Resolver - Build environment variables for Claude CLI
 *
 * Handles:
 * - Remote proxy environment configuration
 * - Local proxy environment configuration
 * - HTTPS tunnel integration
 * - Proxy chain configuration (CodexReasoning, ToolSanitization)
 * - WebSearch and ImageAnalysis hook 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.applyFallback = exports.logEnvironment = exports.buildClaudeEnvironment = exports.resolveCliproxyImageAnalysisEnv = void 0;
const fs = __importStar(require("fs"));
const config_generator_1 = require("../config/config-generator");
const extended_context_config_1 = require("../config/extended-context-config");
const websearch_manager_1 = require("../../utils/websearch-manager");
const get_image_analysis_hook_env_1 = require("../../utils/hooks/get-image-analysis-hook-env");
const image_analysis_runtime_status_1 = require("../../utils/hooks/image-analysis-runtime-status");
const image_analyzer_profile_hook_injector_1 = require("../../utils/hooks/image-analyzer-profile-hook-injector");
const image_analyzer_hook_installer_1 = require("../../utils/hooks/image-analyzer-hook-installer");
const shell_executor_1 = require("../../utils/shell-executor");
const model_id_normalizer_1 = require("../ai-providers/model-id-normalizer");
const auth_token_manager_1 = require("../auth/auth-token-manager");
const config_1 = require("../../types/config");
const defaultCliproxyImageAnalysisDeps = {
    getImageAnalysisHookEnv: get_image_analysis_hook_env_1.getImageAnalysisHookEnv,
    hasImageAnalysisProfileHook: image_analyzer_profile_hook_injector_1.hasImageAnalysisProfileHook,
    hasImageAnalyzerHook: image_analyzer_hook_installer_1.hasImageAnalyzerHook,
    resolveImageAnalysisRuntimeStatus: image_analysis_runtime_status_1.resolveImageAnalysisRuntimeStatus,
    getLocalRuntimeApiKey: auth_token_manager_1.getEffectiveApiKey,
};
const CODEX_EFFORT_SUFFIX_REGEX = /^(.*)-(minimal|low|medium|high|xhigh)$/i;
const EXTENDED_CONTEXT_SUFFIX_REGEX = /\[1m\]$/i;
function normalizeCodexModelForDirectUpstream(model) {
    const withoutExtendedContext = model.trim().replace(EXTENDED_CONTEXT_SUFFIX_REGEX, '').trim();
    if (!withoutExtendedContext)
        return withoutExtendedContext;
    const effortMatch = withoutExtendedContext.match(CODEX_EFFORT_SUFFIX_REGEX);
    if (!effortMatch?.[1] || !effortMatch[2]) {
        return withoutExtendedContext;
    }
    return `${effortMatch[1].trim()}(${effortMatch[2].toLowerCase()})`;
}
function normalizeCodexEnvForDirectUpstream(envVars) {
    let nextEnv = null;
    for (const key of model_id_normalizer_1.MODEL_ENV_VAR_KEYS) {
        const value = envVars[key];
        if (typeof value !== 'string' || value.trim().length === 0)
            continue;
        const normalizedValue = normalizeCodexModelForDirectUpstream(value);
        if (normalizedValue === value)
            continue;
        if (!nextEnv)
            nextEnv = { ...envVars };
        nextEnv[key] = normalizedValue;
    }
    return nextEnv ?? envVars;
}
function loadImageAnalysisSettings(settingsPath) {
    if (!settingsPath) {
        return undefined;
    }
    try {
        if (!fs.existsSync(settingsPath)) {
            return undefined;
        }
        const parsed = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
        return (0, config_1.isSettings)(parsed) ? parsed : undefined;
    }
    catch {
        return undefined;
    }
}
async function resolveCliproxyImageAnalysisEnv(options, deps = {}) {
    const resolvedDeps = { ...defaultCliproxyImageAnalysisDeps, ...deps };
    const settings = loadImageAnalysisSettings(options.profileSettingsPath);
    const context = {
        profileName: options.profileName,
        profileType: 'cliproxy',
        cliproxyProvider: options.provider,
        isComposite: options.isComposite,
        settingsPath: options.profileSettingsPath,
        settings,
        hookInstalled: resolvedDeps.hasImageAnalysisProfileHook(options.profileName, options.profileSettingsPath),
        sharedHookInstalled: resolvedDeps.hasImageAnalyzerHook(),
    };
    const env = resolvedDeps.getImageAnalysisHookEnv(context);
    const currentProvider = env['CCS_CURRENT_PROVIDER'];
    if (env['CCS_IMAGE_ANALYSIS_SKIP'] === '1' || !currentProvider) {
        return { env, warning: null };
    }
    const status = await resolvedDeps.resolveImageAnalysisRuntimeStatus(context, undefined, {
        getProxyTarget: () => options.proxyTarget,
        isCliproxyRunning: async () => options.proxyReachable,
    });
    if (status.effectiveRuntimeMode === 'native-read') {
        return {
            env: {
                ...env,
                CCS_CURRENT_PROVIDER: '',
                CCS_IMAGE_ANALYSIS_SKIP: '1',
            },
            warning: `${status.effectiveRuntimeReason || `Image analysis via ${currentProvider} is unavailable.`} This session will use native Read.`,
        };
    }
    const runtimeConnection = (0, get_image_analysis_hook_env_1.resolveImageAnalysisRuntimeConnection)({
        proxyTarget: options.proxyTarget,
        tunnelPort: options.tunnelPort,
    });
    return {
        env: (0, get_image_analysis_hook_env_1.applyImageAnalysisRuntimeOverrides)(env, {
            backendId: status.backendId,
            model: status.model,
            runtimePath: status.runtimePath,
            baseUrl: runtimeConnection.baseUrl,
            apiKey: options.proxyTarget.isRemote
                ? runtimeConnection.apiKey
                : resolvedDeps.getLocalRuntimeApiKey(),
            allowSelfSigned: runtimeConnection.allowSelfSigned,
        }),
        warning: null,
    };
}
exports.resolveCliproxyImageAnalysisEnv = resolveCliproxyImageAnalysisEnv;
/**
 * Build final environment variables for Claude CLI execution
 * Handles proxy chain ordering and integration with hooks
 */
function buildClaudeEnvironment(config) {
    const { provider, useRemoteProxy, remoteConfig, httpsTunnel, tunnelPort, localPort, customSettingsPath, thinkingOverride, extendedContextOverride, codexReasoningPort, toolSanitizationPort, isComposite, compositeTiers, compositeDefaultTier, claudeConfigDir, imageAnalysisEnv: resolvedImageAnalysisEnv, browserRuntimeEnv, } = config;
    // Build base env vars - check remote mode first
    let envVars;
    if (useRemoteProxy && remoteConfig) {
        if (httpsTunnel && tunnelPort) {
            // HTTPS remote via local tunnel
            if (isComposite && compositeTiers && compositeDefaultTier) {
                envVars = (0, config_generator_1.getCompositeEnvVars)(compositeTiers, compositeDefaultTier, tunnelPort, customSettingsPath, {
                    host: '127.0.0.1',
                    port: tunnelPort,
                    protocol: 'http',
                    authToken: remoteConfig.authToken,
                });
            }
            else {
                envVars = (0, config_generator_1.getRemoteEnvVars)(provider, {
                    host: '127.0.0.1',
                    port: tunnelPort,
                    protocol: 'http', // Tunnel speaks HTTP locally
                    authToken: remoteConfig.authToken,
                }, customSettingsPath);
            }
        }
        else {
            // HTTP remote - direct connection
            if (isComposite && compositeTiers && compositeDefaultTier) {
                envVars = (0, config_generator_1.getCompositeEnvVars)(compositeTiers, compositeDefaultTier, remoteConfig.port, customSettingsPath, {
                    host: remoteConfig.host,
                    port: remoteConfig.port,
                    protocol: remoteConfig.protocol,
                    authToken: remoteConfig.authToken,
                });
            }
            else {
                envVars = (0, config_generator_1.getRemoteEnvVars)(provider, {
                    host: remoteConfig.host,
                    port: remoteConfig.port,
                    protocol: remoteConfig.protocol,
                    authToken: remoteConfig.authToken,
                }, customSettingsPath);
            }
        }
    }
    else {
        // Local proxy mode
        if (isComposite && compositeTiers && compositeDefaultTier) {
            envVars = (0, config_generator_1.getCompositeEnvVars)(compositeTiers, compositeDefaultTier, localPort, customSettingsPath);
        }
        else {
            const remoteRewriteConfig = remoteConfig
                ? {
                    host: remoteConfig.host,
                    port: remoteConfig.port,
                    protocol: remoteConfig.protocol,
                    authToken: remoteConfig.authToken,
                }
                : undefined;
            envVars = (0, config_generator_1.getEffectiveEnvVars)(provider, localPort, customSettingsPath, remoteRewriteConfig);
        }
    }
    // Extract per-tier thinking from composite config
    let compositeTierThinking;
    if (isComposite && compositeTiers) {
        const tierThinking = {};
        if (compositeTiers.opus?.thinking)
            tierThinking.opus = compositeTiers.opus.thinking;
        if (compositeTiers.sonnet?.thinking)
            tierThinking.sonnet = compositeTiers.sonnet.thinking;
        if (compositeTiers.haiku?.thinking)
            tierThinking.haiku = compositeTiers.haiku.thinking;
        if (Object.keys(tierThinking).length > 0) {
            compositeTierThinking = tierThinking;
        }
    }
    // Apply thinking configuration to model (auto tier-based or manual override)
    envVars = (0, config_generator_1.applyThinkingConfig)(envVars, provider, thinkingOverride, compositeTierThinking, compositeTiers);
    // Apply extended context suffix for 1M token context window
    // Auto-enabled for Gemini, opt-in for Claude (--1m flag)
    (0, extended_context_config_1.applyExtendedContextConfig)(envVars, provider, extendedContextOverride);
    // Fallback compatibility for Codex:
    // CLIProxyAPI provider lookup recognizes model(level) suffix form, while CCS stores codex
    // effort aliases as model-level (e.g., gpt-5.3-codex-high). If codex reasoning proxy is
    // unavailable, normalize to model(level) to avoid "unknown provider for model ..." failures.
    if (provider === 'codex' && !isComposite && !codexReasoningPort) {
        envVars = normalizeCodexEnvForDirectUpstream(envVars);
    }
    // Determine the final ANTHROPIC_BASE_URL based on active proxies
    // Chain order: Claude CLI → [CodexReasoningProxy] → [ToolSanitizationProxy] → CLIProxy
    let finalBaseUrl = envVars.ANTHROPIC_BASE_URL;
    if (toolSanitizationPort) {
        finalBaseUrl = `http://127.0.0.1:${toolSanitizationPort}`;
    }
    if (codexReasoningPort) {
        // Codex reasoning proxy is the outermost layer for codex provider
        finalBaseUrl = `http://127.0.0.1:${codexReasoningPort}/api/provider/codex`;
    }
    const effectiveEnvVars = {
        ...envVars,
        ANTHROPIC_BASE_URL: finalBaseUrl,
    };
    // Add hook environment variables
    const webSearchEnv = (0, websearch_manager_1.getWebSearchHookEnv)();
    const imageAnalysisEnv = resolvedImageAnalysisEnv ?? (0, get_image_analysis_hook_env_1.getImageAnalysisHookEnv)(provider);
    // Merge all environment variables (filter undefined values)
    const baseEnv = (0, shell_executor_1.stripBrowserEnv)(Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined)));
    const effectiveEnvVarsFiltered = (0, shell_executor_1.stripBrowserEnv)(Object.fromEntries(Object.entries(effectiveEnvVars).filter(([, v]) => v !== undefined)));
    const mergedEnv = {
        ...baseEnv,
        ...effectiveEnvVarsFiltered,
        ...(claudeConfigDir ? { CLAUDE_CONFIG_DIR: claudeConfigDir } : {}),
        ...webSearchEnv,
        ...imageAnalysisEnv,
        ...(browserRuntimeEnv || {}),
        CCS_PROFILE_TYPE: 'cliproxy', // Signal to WebSearch hook this is a third-party provider
    };
    return Object.fromEntries(Object.entries((0, shell_executor_1.stripClaudeCodeEnv)(mergedEnv)).filter(([, v]) => v !== undefined));
}
exports.buildClaudeEnvironment = buildClaudeEnvironment;
/**
 * Log environment configuration for debugging
 */
function logEnvironment(env, webSearchEnv, verbose) {
    if (!verbose)
        return;
    const log = (msg) => console.error(`[cliproxy] ${msg}`);
    log(`Claude env: ANTHROPIC_BASE_URL=${env.ANTHROPIC_BASE_URL}`);
    log(`Claude env: ANTHROPIC_MODEL=${env.ANTHROPIC_MODEL}`);
    if (Object.keys(webSearchEnv).length > 0) {
        log(`Claude env: WebSearch config=${JSON.stringify(webSearchEnv)}`);
    }
    // Log global env vars for visibility
    if (env.DISABLE_TELEMETRY || env.DISABLE_ERROR_REPORTING || env.DISABLE_BUG_COMMAND) {
        log(`Claude env: Global env applied (telemetry/reporting disabled)`);
    }
}
exports.logEnvironment = logEnvironment;
/** Apply fallback provider config to env vars for a failed tier */
function applyFallback(env, failedTier, fallback) {
    const tierEnvMap = {
        opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
        sonnet: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
        haiku: 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
    };
    const result = { ...env };
    const originalModel = result[tierEnvMap[failedTier]];
    const normalizedFallbackModel = (0, model_id_normalizer_1.normalizeModelIdForProvider)(fallback.model, fallback.provider);
    result[tierEnvMap[failedTier]] = normalizedFallbackModel;
    // If failed tier is default tier, also update ANTHROPIC_MODEL
    if (result.ANTHROPIC_MODEL === originalModel) {
        result.ANTHROPIC_MODEL = normalizedFallbackModel;
    }
    return result;
}
exports.applyFallback = applyFallback;
//# sourceMappingURL=env-resolver.js.map