"use strict";
/**
 * Binary Lifecycle Manager
 * Handles ensuring binary availability and auto-updates.
 */
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.ensureBinary = void 0;
const fs = __importStar(require("fs"));
const version_checker_1 = require("./version-checker");
const installer_1 = require("./installer");
const ui_1 = require("../../utils/ui");
const stats_fetcher_1 = require("../services/stats-fetcher");
const port_manager_1 = require("../config/port-manager");
const platform_detector_1 = require("../binary/platform-detector");
/** Log helper */
function log(message, verbose) {
    if (verbose)
        console.error(`[cliproxy] ${message}`);
}
function getBackendLabel(backend) {
    return backend === 'plus' ? 'CLIProxy Plus' : 'CLIProxy';
}
/**
 * Check if version is above max stable (known unstable)
 */
function isAboveMaxStable(version) {
    return (0, version_checker_1.isNewerVersion)(version, platform_detector_1.CLIPROXY_MAX_STABLE_VERSION);
}
/**
 * Clamp version to max stable if newer versions are unstable
 * Returns max stable version if input is empty/invalid
 */
function clampToMaxStable(version, verbose) {
    if (!version) {
        log(`Empty version, using max stable ${platform_detector_1.CLIPROXY_MAX_STABLE_VERSION}`, verbose);
        return platform_detector_1.CLIPROXY_MAX_STABLE_VERSION;
    }
    if (isAboveMaxStable(version)) {
        log(`Clamping ${version} to max stable ${platform_detector_1.CLIPROXY_MAX_STABLE_VERSION}`, verbose);
        return platform_detector_1.CLIPROXY_MAX_STABLE_VERSION;
    }
    return version;
}
/** Handle auto-update when binary exists */
async function handleAutoUpdate(config, verbose) {
    const backend = config.backend ?? platform_detector_1.DEFAULT_BACKEND;
    const backendLabel = getBackendLabel(backend);
    const checkFn = config.checkForUpdatesFn ?? version_checker_1.checkForUpdates;
    const updateResult = await checkFn(config.binPath, config.version, verbose, backend);
    const currentVersion = updateResult.currentVersion;
    const latestVersion = updateResult.latestVersion;
    // Check if user is on known faulty version - recommend upgrade
    if ((0, version_checker_1.isVersionFaulty)(currentVersion)) {
        console.log((0, ui_1.warn)(`${backendLabel} v${currentVersion} has known bugs (v${platform_detector_1.CLIPROXY_FAULTY_RANGE.min.replace(/-\d+$/, '')}-${platform_detector_1.CLIPROXY_FAULTY_RANGE.max.replace(/-\d+$/, '')}). ` +
            `Upgrade to latest stable recommended.`));
        console.log((0, ui_1.info)(`Run "ccs cliproxy install" to upgrade to latest stable`));
    }
    if (!updateResult.hasUpdate)
        return;
    // Clamp to max stable version
    const targetVersion = clampToMaxStable(latestVersion, verbose);
    if (!(0, version_checker_1.isNewerVersion)(targetVersion, currentVersion)) {
        log(`Already at max stable version ${currentVersion}`, verbose);
        return;
    }
    const proxyRunning = await (0, stats_fetcher_1.isCliproxyRunning)((0, port_manager_1.resolveLifecyclePort)());
    const latestNote = isAboveMaxStable(latestVersion) ? ` (latest v${latestVersion} unstable)` : '';
    const updateMsg = `${backendLabel} update: v${currentVersion} -> v${targetVersion}${latestNote}`;
    if (proxyRunning) {
        console.log((0, ui_1.info)(updateMsg));
        console.log((0, ui_1.info)('Run "ccs cliproxy stop" then restart to apply update'));
        log(`Skipping update: ${backendLabel} is currently running`, verbose);
    }
    else {
        console.log((0, ui_1.info)(updateMsg));
        console.log((0, ui_1.info)(`Updating ${backendLabel}...`));
        (0, installer_1.deleteBinary)(config.binPath, verbose, backend);
        config.version = targetVersion;
        await (0, installer_1.downloadAndInstall)(config, verbose);
    }
}
/**
 * Ensure binary is available (download if missing, update if outdated)
 * @returns Path to executable binary
 */
async function ensureBinary(config) {
    const verbose = config.verbose;
    const backend = config.backend ?? platform_detector_1.DEFAULT_BACKEND;
    const binaryPath = (0, installer_1.getBinaryPath)(config.binPath, backend);
    // Binary exists - check for updates unless forceVersion
    if (fs.existsSync(binaryPath)) {
        log(`Binary exists: ${binaryPath}`, verbose);
        if (config.forceVersion) {
            log('Force version mode: skipping auto-update', verbose);
            return binaryPath;
        }
        if (config.skipAutoUpdate) {
            log('Runtime bootstrap mode: skipping auto-update check', verbose);
            return binaryPath;
        }
        try {
            await handleAutoUpdate(config, verbose);
        }
        catch (error) {
            const err = error;
            log(`Update check failed (non-blocking): ${err.message}`, verbose);
        }
        return binaryPath;
    }
    // Binary missing - download
    log('Binary not found, downloading...', verbose);
    if (!config.allowInstall) {
        throw new Error(`${getBackendLabel(backend)} binary is not installed locally. ` +
            'Run "ccs cliproxy install" when you have network access.');
    }
    if (!config.forceVersion) {
        try {
            const latestVersion = await (0, version_checker_1.fetchLatestVersion)(verbose, backend);
            const targetVersion = clampToMaxStable(latestVersion, verbose);
            if (targetVersion && (0, version_checker_1.isNewerVersion)(targetVersion, config.version)) {
                log(`Using version: ${targetVersion} (instead of ${config.version})`, verbose);
                config.version = targetVersion;
            }
        }
        catch {
            // API failed - use fallback but still clamp to max stable
            const fallbackVersion = clampToMaxStable(config.version, verbose);
            config.version = fallbackVersion;
            log(`Using fallback version: ${fallbackVersion}`, verbose);
        }
    }
    else {
        log(`Force version mode: using specified version ${config.version}`, verbose);
    }
    await (0, installer_1.downloadAndInstall)(config, verbose);
    return binaryPath;
}
exports.ensureBinary = ensureBinary;
//# sourceMappingURL=lifecycle.js.map