"use strict";
/**
 * Proxy Resolver — Concern D
 *
 * Handles proxy configuration resolution, remote proxy reachability check,
 * local-backend selection, and CLIProxy binary acquisition.
 *
 * Extracted from executor/index.ts to isolate the proxy-resolution concern.
 * All log messages, error messages, and exit semantics are byte-identical to
 * the original implementation.
 */
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.resolveExecutorProxy = void 0;
const progress_indicator_1 = require("../../utils/progress-indicator");
const ui_1 = require("../../utils/ui");
const binary_manager_1 = require("../binary-manager");
const remote_proxy_client_1 = require("../services/remote-proxy-client");
const types_1 = require("../types");
const proxy_config_resolver_1 = require("../proxy/proxy-config-resolver");
const config_generator_1 = require("../config/config-generator");
const retry_handler_1 = require("./retry-handler");
/**
 * Resolves proxy configuration, checks remote reachability, selects the local
 * backend, and ensures the CLIProxy binary is present when running locally.
 *
 * Mutates `context.cfg.port` in-place (same as original orchestrator behaviour).
 */
async function resolveExecutorProxy(args, context) {
    const { unifiedConfig, allProviders, verbose: _verbose, cfg, log } = context;
    // Resolve proxy config from CLI flags > ENV > config.yaml > defaults
    const cliproxyServerConfig = unifiedConfig.cliproxy_server;
    const { config: proxyConfig, remainingArgs: argsWithoutProxy } = (0, proxy_config_resolver_1.resolveProxyConfig)(args, {
        remote: cliproxyServerConfig?.remote
            ? {
                enabled: cliproxyServerConfig.remote.enabled,
                host: cliproxyServerConfig.remote.host,
                port: cliproxyServerConfig.remote.port,
                protocol: cliproxyServerConfig.remote.protocol,
                auth_token: cliproxyServerConfig.remote.auth_token,
                management_key: cliproxyServerConfig.remote.management_key,
                timeout: cliproxyServerConfig.remote.timeout,
            }
            : undefined,
        local: cliproxyServerConfig?.local
            ? {
                port: cliproxyServerConfig.local.port,
                auto_start: cliproxyServerConfig.local.auto_start,
            }
            : undefined,
    });
    // Port resolution and validation (mutates cfg in-place)
    if (cfg.port && cfg.port !== config_generator_1.CLIPROXY_DEFAULT_PORT) {
        if (proxyConfig.port !== config_generator_1.CLIPROXY_DEFAULT_PORT) {
            cfg.port = proxyConfig.port;
        }
    }
    else if (proxyConfig.port !== config_generator_1.CLIPROXY_DEFAULT_PORT) {
        cfg.port = proxyConfig.port;
    }
    cfg.port = (0, config_generator_1.validatePort)(cfg.port);
    log(`Proxy mode: ${proxyConfig.mode}`);
    if (proxyConfig.mode === 'remote') {
        log(`Remote host: ${proxyConfig.host}:${proxyConfig.port} (${proxyConfig.protocol})`);
    }
    // Check remote proxy reachability
    let useRemoteProxy = false;
    let localBackend = 'original';
    if (proxyConfig.mode === 'remote' && proxyConfig.host) {
        const status = await (0, remote_proxy_client_1.checkRemoteProxy)({
            host: proxyConfig.host,
            port: proxyConfig.port,
            protocol: proxyConfig.protocol,
            authToken: proxyConfig.authToken,
            timeout: proxyConfig.timeout ?? 2000,
            allowSelfSigned: proxyConfig.allowSelfSigned ?? false,
        });
        if (status.reachable) {
            useRemoteProxy = true;
            console.log((0, ui_1.ok)(`Connected to remote proxy at ${proxyConfig.host}:${proxyConfig.port} (${status.latencyMs}ms)`));
        }
        else {
            console.error((0, ui_1.warn)(`Remote proxy unreachable: ${status.error}`));
            if (proxyConfig.remoteOnly) {
                throw new Error('Remote proxy unreachable and --remote-only specified');
            }
            if (proxyConfig.fallbackEnabled) {
                if (proxyConfig.autoStartLocal) {
                    console.log((0, ui_1.info)('Falling back to local proxy...'));
                }
                else {
                    if (process.stdin.isTTY) {
                        const readline = await Promise.resolve().then(() => __importStar(require('readline')));
                        const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
                        const answer = await new Promise((resolve) => {
                            rl.question('Start local proxy instead? [Y/n] ', resolve);
                        });
                        rl.close();
                        if (answer.toLowerCase() === 'n') {
                            throw new Error('Remote proxy unreachable and user declined fallback');
                        }
                    }
                    console.log((0, ui_1.info)('Starting local proxy...'));
                }
            }
            else {
                throw new Error('Remote proxy unreachable and fallback disabled');
            }
        }
    }
    // Local backend selection (only when not using remote proxy)
    if (!useRemoteProxy) {
        localBackend = (0, binary_manager_1.getConfiguredBackend)({ notifyOnPlus: true });
        for (const p of allProviders) {
            if (localBackend === 'original' && types_1.PLUS_ONLY_PROVIDERS.includes(p)) {
                console.error('');
                console.error((0, ui_1.fail)((0, binary_manager_1.getPlusBackendUnavailableMessage)(p)));
                console.error('');
                throw new Error(`Provider ${p} requires local CLIProxy Plus backend`);
            }
        }
    }
    // Binary acquisition — skipped when using remote proxy
    let binaryPath;
    if (!useRemoteProxy) {
        const spinner = new progress_indicator_1.ProgressIndicator('Preparing CLIProxy');
        spinner.start();
        try {
            binaryPath = await (0, binary_manager_1.ensureCLIProxyBinary)(_verbose, { skipAutoUpdate: true });
            spinner.succeed('CLIProxy binary ready');
        }
        catch (error) {
            spinner.fail('Failed to prepare CLIProxy');
            const err = error;
            if ((0, retry_handler_1.isNetworkError)(err)) {
                (0, retry_handler_1.handleNetworkError)(err);
            }
            throw error;
        }
    }
    return {
        proxyConfig,
        useRemoteProxy,
        localBackend,
        binaryPath,
        argsWithoutProxy,
        cfg,
    };
}
exports.resolveExecutorProxy = resolveExecutorProxy;
//# sourceMappingURL=proxy-resolver.js.map