import { $ } from 'bun';
import { join } from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs';
import { getVersion } from '../version';
/**
 * Checks if a version specifier should be upgraded
 * @param specifier - The version specifier from package.json (e.g., "latest", "^1.0.0", "1.2.3")
 * @returns true if the package should be upgraded
 */
export function shouldUpgradeVersion(specifier) {
    // Always upgrade "latest" and "*"
    if (specifier === 'latest' || specifier === '*') {
        return true;
    }
    // Skip pinned versions (exact semver like "1.2.3")
    if (/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(specifier)) {
        return false;
    }
    // Upgrade ranges (^1.0.0, ~1.0.0, >=1.0.0, etc.)
    // Check if the specifier is a range pattern
    if (/^[~^>=<]/.test(specifier)) {
        return true;
    }
    // Default to not upgrading if we can't determine
    return false;
}
/**
 * Check and upgrade @agentuity/* dependencies to match CLI version
 * @param projectDir - Root directory of the user's project
 * @param logger - Logger instance
 * @returns Result of the upgrade operation
 */
export async function checkAndUpgradeDependencies(projectDir, logger) {
    const result = {
        upgraded: [],
        skipped: [],
        failed: [],
    };
    const cliVersion = getVersion();
    logger.debug('CLI version: %s', cliVersion);
    // check if this is a canary and if so, skip this check
    if (cliVersion.includes('-')) {
        return result;
    }
    const packageJsonPath = join(projectDir, 'package.json');
    // Read package.json
    let packageJson;
    try {
        packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
    }
    catch (error) {
        logger.debug('Failed to read package.json: %s', error);
        return result;
    }
    // Collect all @agentuity/* packages and their original specifiers
    const allDeps = {
        ...packageJson.dependencies,
        ...packageJson.devDependencies,
    };
    const agentuitPackages = Object.entries(allDeps)
        .filter(([name]) => name.startsWith('@agentuity/'))
        .map(([name, specifier]) => ({ name, specifier }));
    if (agentuitPackages.length === 0) {
        logger.debug('No @agentuity/* packages found in package.json');
        return result;
    }
    // Check which packages need upgrading
    const packagesToUpgrade = agentuitPackages.filter(({ specifier }) => shouldUpgradeVersion(specifier));
    if (packagesToUpgrade.length === 0) {
        logger.debug('All @agentuity/* packages are pinned, skipping upgrade');
        for (const pkg of agentuitPackages) {
            result.skipped.push(pkg.name);
        }
        return result;
    }
    // Check if CLI version is different from installed packages
    let needsUpgrade = false;
    for (const { name } of packagesToUpgrade) {
        try {
            const installedPackageJson = JSON.parse(readFileSync(join(projectDir, 'node_modules', name, 'package.json'), 'utf-8'));
            const installedVersion = installedPackageJson.version;
            if (installedVersion !== cliVersion) {
                logger.debug('%s: installed=%s, cli=%s (needs upgrade)', name, installedVersion, cliVersion);
                needsUpgrade = true;
            }
            else {
                logger.debug('%s: already at correct version %s', name, installedVersion);
            }
        }
        catch {
            // Package not installed or can't read version - needs upgrade
            logger.debug('%s: not installed or unreadable, needs upgrade', name);
            needsUpgrade = true;
        }
    }
    if (!needsUpgrade) {
        logger.debug('All @agentuity/* packages are already at CLI version');
        for (const pkg of packagesToUpgrade) {
            result.skipped.push(pkg.name);
        }
        return result;
    }
    // Upgrade packages
    logger.debug('Upgrading %d @agentuity/* package(s) to %s', packagesToUpgrade.length, cliVersion);
    for (const { name } of packagesToUpgrade) {
        try {
            logger.debug('Installing %s@%s', name, cliVersion);
            const installResult = await $ `bun add ${name}@${cliVersion}`
                .cwd(projectDir)
                .quiet()
                .nothrow();
            if (installResult.exitCode !== 0) {
                logger.error('Failed to install %s@%s: %s', name, cliVersion, installResult.stderr.toString());
                result.failed.push(name);
            }
            else {
                logger.debug('Successfully installed %s@%s', name, cliVersion);
                result.upgraded.push(name);
            }
        }
        catch (_error) {
            logger.error('Error installing %s: %s', name, _error);
            result.failed.push(name);
        }
    }
    // Restore original version specifiers in package.json
    // (bun add replaces them with specific versions)
    if (result.upgraded.length > 0) {
        try {
            const updatedPackageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
            let modified = false;
            for (const { name, specifier } of packagesToUpgrade) {
                // Only restore if we successfully upgraded
                if (!result.upgraded.includes(name)) {
                    continue;
                }
                // Check both dependencies and devDependencies
                if (updatedPackageJson.dependencies?.[name]) {
                    updatedPackageJson.dependencies[name] = specifier;
                    modified = true;
                    logger.debug('Restored %s to "%s" in dependencies', name, specifier);
                }
                if (updatedPackageJson.devDependencies?.[name]) {
                    updatedPackageJson.devDependencies[name] = specifier;
                    modified = true;
                    logger.debug('Restored %s to "%s" in devDependencies', name, specifier);
                }
            }
            if (modified) {
                writeFileSync(packageJsonPath, JSON.stringify(updatedPackageJson, null, 2) + '\n');
                logger.debug('Restored original version specifiers in package.json');
            }
        }
        catch (_error) {
            logger.warn('Failed to restore version specifiers in package.json: %s', _error);
        }
    }
    return result;
}
//# sourceMappingURL=dependency-checker.js.map