import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { c as resolvePluginMetadataSnapshot } from "./plugin-metadata-snapshot-Bkwllh-7.js";
import { i as listAgentEntries, p as resolveAgentWorkspaceDir, u as resolveAgentDir, w as tryResolveDefaultAgentId } from "./agent-scope-config-adSj-fCz.js";
import { c as normalizeProviderId } from "./model-ref-shared-DflvAb3G.js";
import { n as DEFAULT_MODEL, r as DEFAULT_PROVIDER } from "./defaults-CdX9UGcX.js";
import "./agent-scope-CB42Y_8g.js";
import { t as listMutableCodexRouteAgentEntries } from "./codex-route-agent-entries-D1gMHnMO.js";
import "./model-selection-CtjI2iP7.js";
import { n as resolveProviderInstallCatalogEntries } from "./provider-install-catalog-lXcJdNtG.js";
import { r as collectConfiguredProviderSelectionIds } from "./configured-provider-selection-ids-CTLewJx9.js";
import fs from "node:fs";
import path from "node:path";
//#region src/commands/doctor/shared/stale-agent-model-ref-repair.ts
const DEFAULT_MODEL_REF = `${DEFAULT_PROVIDER}/${DEFAULT_MODEL}`;
function providerFromModelRef(ref) {
	const trimmed = ref.trim();
	const slash = trimmed.indexOf("/");
	if (slash <= 0 || slash === trimmed.length - 1) return;
	return normalizeProviderId(trimmed.slice(0, slash)) || void 0;
}
function collectPluginProviderIds(cfg, options) {
	let providerIds;
	if (options.pluginProviderIds) providerIds = new Set([...options.pluginProviderIds].map(normalizeProviderId).filter(Boolean));
	else {
		const defaultAgentId = tryResolveDefaultAgentId(cfg);
		const workspaceDir = defaultAgentId ? resolveAgentWorkspaceDir(cfg, defaultAgentId) : void 0;
		const snapshot = options.pluginMetadataSnapshot ?? resolvePluginMetadataSnapshot({
			config: cfg,
			workspaceDir: workspaceDir ?? void 0,
			env: options.env ?? process.env,
			allowWorkspaceScopedCurrent: true
		});
		if (snapshot.diagnostics.some((diagnostic) => diagnostic.level === "error")) return { warnings: ["Skipped stale agent model reference repair because plugin discovery reported errors."] };
		providerIds = /* @__PURE__ */ new Set();
		for (const owners of [
			snapshot.owners.providers,
			snapshot.owners.modelCatalogProviders,
			snapshot.owners.setupProviders,
			snapshot.owners.cliBackends
		]) for (const providerId of owners.keys()) {
			const normalized = normalizeProviderId(providerId);
			if (normalized) providerIds.add(normalized);
		}
	}
	const selectedProviderIds = collectConfiguredProviderSelectionIds(cfg);
	for (const entry of resolveProviderInstallCatalogEntries({
		config: cfg,
		env: options.env ?? process.env,
		includeUntrustedWorkspacePlugins: false
	})) {
		const entryProviderIds = [entry.providerId, ...entry.providerAliases ?? []];
		if (!entryProviderIds.some((providerId) => selectedProviderIds.has(providerId.toLowerCase()))) continue;
		for (const providerId of entryProviderIds) {
			const normalized = normalizeProviderId(providerId);
			if (normalized) providerIds.add(normalized);
		}
	}
	return {
		providerIds,
		warnings: []
	};
}
function collectPersistedProviderIds(params) {
	const injected = params.injected?.get(params.agentId);
	if (injected) return { providerIds: new Set([...injected].map(normalizeProviderId).filter(Boolean)) };
	if (params.injected) return { providerIds: /* @__PURE__ */ new Set() };
	const modelsPath = path.join(resolveAgentDir(params.cfg, params.agentId, params.env), "models.json");
	let raw;
	try {
		raw = fs.readFileSync(modelsPath, "utf8");
	} catch (error) {
		if (error.code === "ENOENT") return { providerIds: /* @__PURE__ */ new Set() };
		return { warning: `Skipped stale model reference repair for agent "${params.agentId}" because ${modelsPath} could not be read.` };
	}
	try {
		const parsed = JSON.parse(raw);
		if (!parsed.providers || typeof parsed.providers !== "object" || Array.isArray(parsed.providers)) return { providerIds: /* @__PURE__ */ new Set() };
		return { providerIds: new Set(Object.keys(parsed.providers).map(normalizeProviderId).filter(Boolean)) };
	} catch {
		return { warning: `Skipped stale model reference repair for agent "${params.agentId}" because ${modelsPath} is invalid JSON.` };
	}
}
function repairModelMap(params) {
	if (!isRecord(params.models)) return;
	const refs = Object.keys(params.models);
	const staleRefs = refs.filter((ref) => params.isStale(ref));
	if (staleRefs.length === refs.length && staleRefs.length > 0 && !params.replacementRef) {
		params.warnings.push(`Skipped clearing ${params.path} because no available replacement model could keep the allowlist restrictive.`);
		return;
	}
	for (const ref of staleRefs) {
		const provider = params.isStale(ref);
		delete params.models[ref];
		params.changes.push(`Removed stale ${params.path} entry "${ref}" (provider "${provider}" is unavailable).`);
	}
	if (refs.length > 0 && (staleRefs.length > 0 || params.ensureReplacement === true) && params.replacementRef && !Object.hasOwn(params.models, params.replacementRef)) {
		params.models[params.replacementRef] = {};
		params.changes.push(`Added ${params.path} entry "${params.replacementRef}" to keep the repaired allowlist restrictive.`);
	}
}
function filterFallbacks(params) {
	if (!Array.isArray(params.model.fallbacks)) return;
	params.model.fallbacks = params.model.fallbacks.filter((ref) => {
		if (typeof ref !== "string") return true;
		const provider = params.isStale(ref);
		if (!provider) return true;
		params.changes.push(`Removed stale ${params.path} fallback "${ref}" (provider "${provider}" is unavailable).`);
		return false;
	});
	if (params.model.fallbacks.length === 0) delete params.model.fallbacks;
}
function firstExplicitModelRef(cfg) {
	if (!isRecord(cfg.models?.providers)) return;
	for (const [providerId, provider] of Object.entries(cfg.models.providers)) {
		if (!isRecord(provider) || !Array.isArray(provider.models)) continue;
		const normalizedProvider = normalizeProviderId(providerId);
		const modelId = provider.models.map((model) => isRecord(model) && typeof model.id === "string" ? model.id.trim() : "").find(Boolean);
		if (normalizedProvider && modelId) return `${normalizedProvider}/${modelId}`;
	}
}
function modelPrimaryRef(model) {
	if (typeof model === "string") return model;
	return isRecord(model) && typeof model.primary === "string" ? model.primary : void 0;
}
function repairStaleAgentModelRefs(cfg, options = {}) {
	const replaceMode = cfg.models?.mode === "replace";
	const pluginProviders = replaceMode ? {
		providerIds: /* @__PURE__ */ new Set(),
		warnings: []
	} : collectPluginProviderIds(cfg, options);
	if (!pluginProviders.providerIds) return {
		config: cfg,
		changes: [],
		warnings: pluginProviders.warnings
	};
	const baseAvailableProviders = pluginProviders.providerIds;
	if (!replaceMode) baseAvailableProviders.add(normalizeProviderId(DEFAULT_PROVIDER));
	for (const providerId of Object.keys(cfg.models?.providers ?? {})) {
		const normalized = normalizeProviderId(providerId);
		if (normalized) baseAvailableProviders.add(normalized);
	}
	const config = structuredClone(cfg);
	const changes = [];
	const warnings = [...pluginProviders.warnings];
	const env = options.env ?? process.env;
	const persistedForAgent = (agentId) => {
		const persisted = collectPersistedProviderIds({
			cfg,
			agentId,
			env,
			injected: options.persistedProviderIdsByAgentId
		});
		if (!persisted.providerIds) {
			if (persisted.warning) warnings.push(persisted.warning);
			return;
		}
		return persisted.providerIds;
	};
	const availabilityForAgent = (agentId) => {
		const available = new Set(baseAvailableProviders);
		if (replaceMode) return available;
		const persisted = persistedForAgent(agentId);
		if (!persisted) return;
		for (const providerId of persisted) available.add(providerId);
		return available;
	};
	const availabilityForDefaults = () => {
		const available = new Set(baseAvailableProviders);
		if (replaceMode) return available;
		const inheritingAgentIds = [];
		for (const agent of listAgentEntries(cfg)) {
			if (typeof agent.id !== "string") continue;
			const explicitPrimary = modelPrimaryRef(agent.model);
			if (!explicitPrimary) {
				inheritingAgentIds.push(agent.id);
				continue;
			}
			const agentAvailability = availabilityForAgent(agent.id);
			const provider = providerFromModelRef(explicitPrimary);
			if (agentAvailability && provider && !agentAvailability.has(provider)) inheritingAgentIds.push(agent.id);
		}
		if (inheritingAgentIds.length === 0) {
			const defaultAgentId = tryResolveDefaultAgentId(cfg);
			if (defaultAgentId) inheritingAgentIds.push(defaultAgentId);
		}
		let commonPersisted;
		for (const agentId of inheritingAgentIds) {
			const persisted = persistedForAgent(agentId);
			if (!persisted) return;
			commonPersisted = commonPersisted ? new Set([...commonPersisted].filter((providerId) => persisted.has(providerId))) : new Set(persisted);
		}
		for (const providerId of commonPersisted ?? []) available.add(providerId);
		return available;
	};
	const availabilityForDefaultModelMap = () => {
		const available = new Set(baseAvailableProviders);
		if (replaceMode) return available;
		const inheritingAgentIds = listAgentEntries(cfg).filter((agent) => isRecord(agent) && typeof agent.id === "string" && !isRecord(agent.models)).map((agent) => agent.id);
		if (inheritingAgentIds.length === 0) {
			const defaultAgentId = tryResolveDefaultAgentId(cfg);
			if (defaultAgentId) inheritingAgentIds.push(defaultAgentId);
		}
		for (const agentId of inheritingAgentIds) {
			const persisted = persistedForAgent(agentId);
			if (!persisted) return;
			for (const providerId of persisted) available.add(providerId);
		}
		return available;
	};
	const makeStaleChecker = (available) => (ref) => {
		const provider = providerFromModelRef(ref);
		return provider && !available.has(provider) ? provider : void 0;
	};
	const defaults = config.agents?.defaults;
	const defaultAvailability = availabilityForDefaults();
	let repairedDefaultPrimary = modelPrimaryRef(defaults?.model) ?? (replaceMode ? firstExplicitModelRef(cfg) : DEFAULT_MODEL_REF);
	let defaultPrimaryChanged = false;
	if (defaults && defaultAvailability) {
		const isStale = makeStaleChecker(defaultAvailability);
		const configuredReplacement = replaceMode ? firstExplicitModelRef(cfg) : DEFAULT_MODEL_REF;
		if (defaults.model) {
			if (typeof defaults.model === "string") {
				const provider = isStale(defaults.model);
				if (provider) {
					const staleRef = defaults.model;
					if (configuredReplacement) {
						defaults.model = configuredReplacement;
						defaultPrimaryChanged = true;
						changes.push(`Replaced stale agents.defaults.model "${staleRef}" with default "${configuredReplacement}" (provider "${provider}" is unavailable).`);
					} else {
						delete defaults.model;
						defaultPrimaryChanged = true;
						changes.push(`Removed stale agents.defaults.model "${staleRef}" because provider "${provider}" is unavailable and no replacement model is configured.`);
					}
				}
			} else if (isRecord(defaults.model)) {
				const provider = typeof defaults.model.primary === "string" ? isStale(defaults.model.primary) : void 0;
				let replacement;
				if (provider && typeof defaults.model.primary === "string") {
					const staleRef = defaults.model.primary;
					replacement = replaceMode ? (Array.isArray(defaults.model.fallbacks) ? defaults.model.fallbacks.find((fallback) => typeof fallback === "string" && !isStale(fallback)) : void 0) ?? configuredReplacement : configuredReplacement;
					if (replacement) {
						defaults.model.primary = replacement;
						defaultPrimaryChanged = true;
						changes.push(`Replaced stale agents.defaults.model primary "${staleRef}" with default "${replacement}" (provider "${provider}" is unavailable).`);
					} else {
						delete defaults.model.primary;
						defaultPrimaryChanged = true;
						changes.push(`Removed stale agents.defaults.model primary "${staleRef}" because provider "${provider}" is unavailable and no replacement model is configured.`);
					}
				}
				filterFallbacks({
					model: defaults.model,
					path: "agents.defaults.model",
					isStale,
					changes
				});
				if (replacement && Array.isArray(defaults.model.fallbacks) && defaults.model.fallbacks.includes(replacement)) {
					defaults.model.fallbacks = defaults.model.fallbacks.filter((fallback) => fallback !== replacement);
					changes.push(`Removed duplicate agents.defaults.model fallback "${replacement}" after selecting it as the default primary.`);
					if (defaults.model.fallbacks.length === 0) delete defaults.model.fallbacks;
				}
				if (!defaults.model.primary && !defaults.model.fallbacks) delete defaults.model;
			}
		}
		repairedDefaultPrimary = modelPrimaryRef(defaults.model) ?? (replaceMode ? firstExplicitModelRef(cfg) : DEFAULT_MODEL_REF);
		const modelMapAvailability = availabilityForDefaultModelMap();
		if (modelMapAvailability) repairModelMap({
			models: defaults.models,
			path: "agents.defaults.models",
			isStale: makeStaleChecker(modelMapAvailability),
			replacementRef: repairedDefaultPrimary,
			ensureReplacement: defaultPrimaryChanged,
			changes,
			warnings
		});
	}
	for (const entry of listMutableCodexRouteAgentEntries(config)) {
		const agent = entry.agent;
		const available = availabilityForAgent(entry.agentId);
		if (!available) continue;
		const isStale = makeStaleChecker(available);
		const modelPath = `${entry.path}.model`;
		const canInheritDefault = Boolean(defaultAvailability && repairedDefaultPrimary && (!replaceMode || modelPrimaryRef(defaults?.model)) && !isStale(repairedDefaultPrimary));
		let agentPrimaryChanged = false;
		if (typeof agent.model === "string") {
			const provider = isStale(agent.model);
			if (provider) {
				const staleRef = agent.model;
				if (canInheritDefault) {
					delete agent.model;
					agentPrimaryChanged = true;
					changes.push(`Removed stale ${modelPath} "${staleRef}" so agent "${entry.agentId}" inherits the default model (provider "${provider}" is unavailable).`);
				} else if (repairedDefaultPrimary && !isStale(repairedDefaultPrimary)) {
					agent.model = repairedDefaultPrimary;
					agentPrimaryChanged = true;
					changes.push(`Replaced stale ${modelPath} "${staleRef}" with "${repairedDefaultPrimary}" (provider "${provider}" is unavailable).`);
				} else warnings.push(`Skipped stale ${modelPath} repair because no available inherited or replacement model is configured.`);
			}
		} else if (isRecord(agent.model)) {
			const model = agent.model;
			const provider = typeof model.primary === "string" ? isStale(model.primary) : void 0;
			let agentReplacement;
			if (provider && typeof model.primary === "string") {
				const staleRef = model.primary;
				if (canInheritDefault) {
					delete model.primary;
					agentPrimaryChanged = true;
					agentReplacement = repairedDefaultPrimary;
					changes.push(`Removed stale ${modelPath} primary "${staleRef}" so agent "${entry.agentId}" inherits the default model (provider "${provider}" is unavailable).`);
				} else if (agentReplacement = (Array.isArray(model.fallbacks) ? model.fallbacks.find((fallback) => typeof fallback === "string" && !isStale(fallback)) : void 0) ?? (repairedDefaultPrimary && !isStale(repairedDefaultPrimary) ? repairedDefaultPrimary : void 0)) {
					model.primary = agentReplacement;
					agentPrimaryChanged = true;
					changes.push(`Replaced stale ${modelPath} primary "${staleRef}" with "${agentReplacement}" (provider "${provider}" is unavailable).`);
				} else warnings.push(`Skipped stale ${modelPath} primary repair because no available inherited or replacement model is configured.`);
			}
			filterFallbacks({
				model,
				path: modelPath,
				isStale,
				changes
			});
			if (agentReplacement && Array.isArray(model.fallbacks) && model.fallbacks.includes(agentReplacement)) {
				const filteredFallbacks = model.fallbacks.filter((fallback) => fallback !== agentReplacement);
				model.fallbacks = filteredFallbacks;
				changes.push(`Removed duplicate ${modelPath} fallback "${agentReplacement}" after selecting it as the primary.`);
				if (filteredFallbacks.length === 0) delete model.fallbacks;
			}
			if (!model.primary && !model.fallbacks) delete agent.model;
		}
		const effectiveAgentPrimary = modelPrimaryRef(agent.model) ?? repairedDefaultPrimary;
		repairModelMap({
			models: isRecord(agent.models) ? agent.models : void 0,
			path: `${entry.path}.models`,
			isStale,
			replacementRef: effectiveAgentPrimary && !isStale(effectiveAgentPrimary) ? effectiveAgentPrimary : void 0,
			ensureReplacement: agentPrimaryChanged || !modelPrimaryRef(agent.model) && defaultPrimaryChanged,
			changes,
			warnings
		});
	}
	return {
		config: changes.length > 0 ? config : cfg,
		changes,
		warnings
	};
}
//#endregion
export { repairStaleAgentModelRefs as t };
