import { AGENTS } from '../agents.js';
import { getGlobalDefault } from './versions.js';
import { listInstallations } from './store.js';
/**
 * Addressing a frozen installation.
 *
 * A selector matches either the installation's stable {@link Installation.label}
 * or the vendor release it currently carries — the label because that is what
 * every persisted reference and every `agents add` invocation uses, the release
 * because after an update the two differ and a user reading `agents view` may
 * name either. Matching both is also precisely what makes duplicate same-release
 * installations addressable at all: two installs can share a release, so the
 * release alone is not an identifier and the ambiguity has to be reported rather
 * than silently resolved to whichever sorted first.
 */
export class InstallationNotFoundError extends Error {
    agent;
    selector;
    available;
    constructor(agent, selector, available) {
        // Nothing installed is a different problem from "your selector missed", and
        // the remedy differs — say which one it is rather than printing an empty list.
        super(available.length === 0
            ? `No ${AGENTS[agent].name} installations are managed by agents-cli. Install one with: agents add ${agent}@latest`
            : `No ${AGENTS[agent].name} installation matches '${selector}'. Installed: ${available.map((i) => describeInstallation(i)).join(', ')}`);
        this.agent = agent;
        this.selector = selector;
        this.available = available;
        this.name = 'InstallationNotFoundError';
    }
}
export class InstallationAmbiguousError extends Error {
    agent;
    selector;
    candidates;
    constructor(agent, selector, candidates) {
        super(`'${selector ?? agent}' matches ${candidates.length} ${AGENTS[agent].name} installations `
            + `(${candidates.map((i) => describeInstallation(i)).join(', ')}). `
            + `Select one by its installation label.`);
        this.agent = agent;
        this.selector = selector;
        this.candidates = candidates;
        this.name = 'InstallationAmbiguousError';
    }
}
/** `2.0.65` when frozen at its original release, `2.0.65 (release 2.0.71)` after an update. */
export function describeInstallation(installation) {
    return installation.releaseVersion === installation.label
        ? installation.label
        : `${installation.label} (release ${installation.releaseVersion})`;
}
/**
 * Resolve `<agent>[@<selector>]` to exactly one installation.
 *
 * With no selector: the agent's default installation when one is pinned, else
 * the sole installation. Never a "newest wins" guess — picking for the user
 * across several installs is how an update lands on the wrong one.
 */
export async function resolveInstallation(agent, selector, options = {}) {
    const all = listInstallations(agent);
    if (all.length === 0)
        throw new InstallationNotFoundError(agent, selector, all);
    let candidates = all;
    if (options.account) {
        throw new Error("--account no longer selects an installation. Account names are durable credentials used by 'agents run --account'; select the installation by its label instead.");
    }
    if (selector) {
        const byLabel = candidates.filter((i) => i.label === selector);
        // A label is unique by construction (it is a directory name), so a label hit
        // is decisive and never competes with a release hit on another installation.
        if (byLabel.length === 1)
            return byLabel[0];
        const byRelease = candidates.filter((i) => i.releaseVersion === selector);
        if (byRelease.length === 1)
            return byRelease[0];
        if (byRelease.length > 1)
            throw new InstallationAmbiguousError(agent, selector, byRelease);
        throw new InstallationNotFoundError(agent, selector, all);
    }
    if (candidates.length === 1)
        return candidates[0];
    const defaultLabel = getGlobalDefault(agent);
    const pinned = defaultLabel ? candidates.find((i) => i.label === defaultLabel) : undefined;
    if (pinned)
        return pinned;
    throw new InstallationAmbiguousError(agent, selector, candidates);
}
