"use strict";
/**
 * Version Checker
 * Handles checking GitHub API for latest version and comparing semver.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchAllVersions = exports.checkForUpdates = exports.fetchLatestVersion = exports.isVersionFaulty = exports.isNewerVersion = void 0;
const downloader_1 = require("./downloader");
const version_cache_1 = require("./version-cache");
const types_1 = require("./types");
const platform_detector_1 = require("../binary/platform-detector");
/**
 * Compare semver versions (true if latest > current)
 * Handles CLIProxyAPIPlus versioning: strips -0 suffix before comparison
 */
function isNewerVersion(latest, current) {
    // Strip -0 suffix from CLIProxyAPIPlus versions (e.g., "6.6.40-0" -> "6.6.40")
    const cleanLatest = latest.replace(/-\d+$/, '');
    const cleanCurrent = current.replace(/-\d+$/, '');
    const latestParts = cleanLatest.split('.').map((p) => parseInt(p, 10) || 0);
    const currentParts = cleanCurrent.split('.').map((p) => parseInt(p, 10) || 0);
    // Pad arrays to same length
    while (latestParts.length < 3)
        latestParts.push(0);
    while (currentParts.length < 3)
        currentParts.push(0);
    for (let i = 0; i < 3; i++) {
        if (latestParts[i] > currentParts[i])
            return true;
        if (latestParts[i] < currentParts[i])
            return false;
    }
    return false; // Equal versions
}
exports.isNewerVersion = isNewerVersion;
/**
 * Check if version is within the faulty range (v81-85)
 * @returns true if version has known critical bugs
 */
function isVersionFaulty(version) {
    const { min, max } = platform_detector_1.CLIPROXY_FAULTY_RANGE;
    const atOrAboveMin = !isNewerVersion(min, version); // version >= min
    const atOrBelowMax = !isNewerVersion(version, max); // version <= max
    return atOrAboveMin && atOrBelowMax;
}
exports.isVersionFaulty = isVersionFaulty;
/**
 * Fetch latest version from GitHub API
 * @param verbose Enable verbose logging
 * @param backend Backend to fetch version for (uses correct GitHub repo)
 */
async function fetchLatestVersion(verbose = false, backend = platform_detector_1.DEFAULT_BACKEND, deps = {}) {
    const urls = (0, types_1.getGitHubApiUrls)(backend);
    const response = await (deps.fetchJsonFn ?? downloader_1.fetchJson)(urls.latestRelease, verbose);
    // Extract version from tag_name (format: "v6.5.27" or "6.5.27")
    const tagName = response.tag_name;
    if (!tagName) {
        throw new Error('No tag_name in GitHub API response');
    }
    return tagName.replace(/^v/, '');
}
exports.fetchLatestVersion = fetchLatestVersion;
/**
 * Check for updates by comparing installed version with latest release
 * Uses cache to avoid hitting GitHub API on every run
 * Cache is backend-specific to handle different repos for original vs plus
 */
async function checkForUpdates(binPath, configVersion, verbose = false, backend = platform_detector_1.DEFAULT_BACKEND, deps = {}) {
    const currentVersion = (0, version_cache_1.readInstalledVersion)(binPath, configVersion);
    // Try cache first (backend-specific)
    const cache = (0, version_cache_1.readVersionCache)(backend);
    if (cache) {
        if (verbose) {
            console.error(`[cliproxy] Using cached version: ${cache.latestVersion}`);
        }
        return {
            hasUpdate: isNewerVersion(cache.latestVersion, currentVersion),
            currentVersion,
            latestVersion: cache.latestVersion,
            fromCache: true,
            checkedAt: cache.checkedAt,
        };
    }
    try {
        // Fetch from GitHub API (backend-specific repo)
        const latestVersion = await (deps.fetchLatestVersionFn ?? fetchLatestVersion)(verbose, backend);
        const now = Date.now();
        (0, version_cache_1.writeVersionCache)(latestVersion, backend);
        return {
            hasUpdate: isNewerVersion(latestVersion, currentVersion),
            currentVersion,
            latestVersion,
            fromCache: false,
            checkedAt: now,
        };
    }
    catch (error) {
        const staleCache = (0, version_cache_1.readStaleVersionCache)(backend);
        if (staleCache) {
            if (verbose) {
                console.error(`[cliproxy] GitHub latest release lookup failed, using stale cache: ${error.message}`);
            }
            return {
                hasUpdate: isNewerVersion(staleCache.latestVersion, currentVersion),
                currentVersion,
                latestVersion: staleCache.latestVersion,
                fromCache: true,
                checkedAt: staleCache.checkedAt,
            };
        }
        throw error;
    }
}
exports.checkForUpdates = checkForUpdates;
/**
 * Fetch all available versions from GitHub releases
 * Caches result for 1 hour to avoid rate limiting
 * @param verbose Enable verbose logging
 * @param backend Backend to fetch versions for (uses correct GitHub repo)
 */
async function fetchAllVersions(verbose = false, backend = platform_detector_1.DEFAULT_BACKEND, deps = {}) {
    // Try cache first (backend-specific)
    const cache = (0, version_cache_1.readVersionListCache)(backend);
    if (cache) {
        if (verbose) {
            console.error(`[cliproxy] Using cached version list (${cache.versions.length} versions)`);
        }
        return { ...cache, fromCache: true };
    }
    try {
        // Fetch from GitHub API (backend-specific repo)
        const urls = (0, types_1.getGitHubApiUrls)(backend);
        const response = await (deps.fetchJsonFn ?? downloader_1.fetchJson)(urls.allReleases, verbose);
        // Extract and normalize versions
        const releases = response;
        const versions = releases
            .map((r) => r.tag_name.replace(/^v/, ''))
            .filter((v) => /^\d+\.\d+\.\d+(-\d+)?$/.test(v)); // Valid semver only
        const latest = versions[0] || '';
        // Find latest stable (not newer than max stable AND not in faulty range)
        const latestStable = versions.find((v) => !isNewerVersion(v, platform_detector_1.CLIPROXY_MAX_STABLE_VERSION) && !isVersionFaulty(v)) || platform_detector_1.CLIPROXY_MAX_STABLE_VERSION;
        const result = {
            versions,
            latestStable,
            latest,
            fromCache: false,
            checkedAt: Date.now(),
        };
        (0, version_cache_1.writeVersionListCache)(result, backend);
        return result;
    }
    catch (error) {
        const staleCache = (0, version_cache_1.readStaleVersionListCache)(backend);
        if (staleCache) {
            if (verbose) {
                console.error(`[cliproxy] GitHub release list lookup failed, using stale cache: ${error.message}`);
            }
            return { ...staleCache, fromCache: true };
        }
        throw error;
    }
}
exports.fetchAllVersions = fetchAllVersions;
//# sourceMappingURL=version-checker.js.map