"use strict";
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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateInstallations = updateInstallations;
const fs = __importStar(require("fs"));
const inquirer = __importStar(require("inquirer"));
const cliUtil_1 = require("@mablhq-internal/runtime/core/cliUtil");
const agentInstallRegistry_1 = require("../../../util/agentInstallRegistry");
const shared_1 = require("../shared");
const install_1 = require("./install");
exports.command = 'update';
exports.describe = 'Refresh tracked agent skills after upgrading the CLI';
exports.builder = (yargs) => {
    yargs
        .option('target', {
        describe: `Only update installations for this target (${shared_1.SUPPORTED_TARGETS.join(', ')})`,
        type: 'string',
        choices: shared_1.SUPPORTED_TARGETS,
    })
        .option('scope', {
        describe: `Only update installations at this scope (${shared_1.SUPPORTED_SCOPES.join(' or ')})`,
        type: 'string',
        choices: shared_1.SUPPORTED_SCOPES,
    })
        .option('yes', {
        alias: 'y',
        describe: 'Update every matching stale installation without prompting',
        type: 'boolean',
        default: false,
    })
        .option('quiet', {
        describe: 'Suppress informational output; only print prune notices, errors, and the final summary when an update actually happened',
        type: 'boolean',
        default: false,
    });
};
exports.handler = (0, cliUtil_1.failWrapper)(updateInstallations);
async function updateInstallations(parsed) {
    const currentVersion = (0, agentInstallRegistry_1.readCliVersion)();
    if (!currentVersion) {
        throw new Error('Could not determine the current mabl-cli version. Refusing to update.');
    }
    const verbose = !parsed.quiet;
    const { pruned } = (0, agentInstallRegistry_1.pruneMissingArtifacts)();
    if (pruned.length > 0) {
        process.stdout.write(`Removed ${pruned.length} tracked installation${pruned.length === 1 ? '' : 's'} whose skill file no longer exists.\n`);
    }
    const registry = (0, agentInstallRegistry_1.readRegistry)();
    const matched = registry.installations.filter((entry) => matchesFilters(entry, parsed.target, parsed.scope));
    if (matched.length === 0) {
        if (verbose) {
            process.stdout.write('No tracked agent skills match the given filters.\n');
        }
        return;
    }
    const stale = matched.filter((entry) => entry.cliVersion !== currentVersion);
    const upToDate = matched.filter((entry) => entry.cliVersion === currentVersion);
    if (verbose && upToDate.length > 0) {
        process.stdout.write(`Up to date (${upToDate.length}):\n` +
            upToDate
                .map((entry) => `  ${describeEntry(entry)} @ ${entry.cliVersion}\n`)
                .join(''));
    }
    if (stale.length === 0) {
        if (verbose) {
            process.stdout.write('All matching installations are up to date.\n');
        }
        return;
    }
    if (verbose) {
        process.stdout.write(`\nStale (${stale.length}, current CLI version: ${currentVersion}):\n` +
            stale
                .map((entry) => `  ${describeEntry(entry)} — recorded version ${entry.cliVersion}\n`)
                .join('') +
            '\n');
    }
    let updated = 0;
    let skipped = 0;
    for (const entry of stale) {
        const shouldUpdate = parsed.yes || (await promptYesNo(`Update ${describeEntry(entry)}?`));
        if (!shouldUpdate) {
            skipped += 1;
            continue;
        }
        try {
            await reinstallEntry(entry, parsed.quiet);
            updated += 1;
        }
        catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            process.stderr.write(`  Failed to update ${describeEntry(entry)}: ${message}\n`);
        }
    }
    if (verbose || updated > 0) {
        process.stdout.write(`\nDone. Updated ${updated} of ${stale.length} stale installation${stale.length === 1 ? '' : 's'}${skipped > 0 ? ` (${skipped} skipped)` : ''}.\n`);
    }
}
function matchesFilters(entry, target, scope) {
    if (target && entry.target !== target) {
        return false;
    }
    if (scope && entry.scope !== scope) {
        return false;
    }
    return true;
}
function describeEntry(entry) {
    if (entry.scope === shared_1.SupportedScope.Project && entry.projectPath) {
        return `${entry.target} (project: ${(0, shared_1.homeRelative)(entry.projectPath)})`;
    }
    return `${entry.target} (${entry.scope})`;
}
async function reinstallEntry(entry, quiet) {
    const skipMcp = !entry.artifacts.some((a) => a.type === agentInstallRegistry_1.ArtifactType.McpEntry);
    const appendSnippet = entry.artifacts.some((a) => a.type === agentInstallRegistry_1.ArtifactType.Snippet);
    const originalCwd = process.cwd();
    let didChdir = false;
    if (entry.scope === shared_1.SupportedScope.Project) {
        if (!entry.projectPath) {
            throw new Error('Project-scoped entry is missing its projectPath.');
        }
        if (!fs.existsSync(entry.projectPath)) {
            throw new Error(`Project directory ${entry.projectPath} no longer exists.`);
        }
        process.chdir(entry.projectPath);
        didChdir = true;
    }
    try {
        const installArgs = {
            target: entry.target,
            scope: entry.scope,
            force: true,
            'skip-mcp': skipMcp,
            'append-snippet': appendSnippet,
        };
        await (0, install_1.installSkill)(installArgs, { quiet });
    }
    finally {
        if (didChdir) {
            process.chdir(originalCwd);
        }
    }
}
async function promptYesNo(question) {
    const answer = await inquirer.prompt([
        {
            type: 'confirm',
            name: 'confirm',
            message: question,
            default: false,
        },
    ]);
    return Boolean(answer.confirm);
}
