/**
 * solver-model.js — pinned model selection for the autonomous solver role.
 *
 * Why this exists:
 *   The "executor" and "autonomous solver" roles were historically conflated
 *   into a single LLM call selected by the unit-type router. When the router
 *   picked a coding-tuned or capability-limited model for the executor (e.g.
 *   `mistral/codestral-latest`, `google-gemini-cli/gemini-3-flash-preview`),
 *   the same model was expected to (a) do the unit work and (b) emit the
 *   canonical protocol checkpoint. Models that refuse agentic tasks or fail
 *   to follow tool-use contracts broke the protocol layer entirely — and the
 *   missing-checkpoint repair loop could only re-prompt the same broken
 *   model, synthesizing fake `continue` outcomes over zero progress.
 *
 *   The solver role MUST stay on a stable, agentic, refusal-resistant model
 *   independent of any per-unit routing choices. This module is the single
 *   place that decision is made.
 *
 * Contract:
 *   - Default solver model is `kimi-k2.6` (provider: `kimi-coding`).
 *   - Preference override is accepted ONLY when the operator has explicitly
 *     opted into it via `preferences.autonomousSolver.model`. Router output,
 *     benchmark scoring, learning blender, and unit-type routing are NEVER
 *     consulted here.
 *   - A fallback chain is provided so a brief outage of the primary does not
 *     take the protocol layer with it.
 *
 * Consumers (forthcoming): the solver-pass invocation in auto/phases-unit.js
 * once the two-layer loop lands (see ADR-0079).
 */

/**
 * Default model for the autonomous solver role. Locked. Do not change without
 * an ADR update — this is a protocol invariant, not a tuning parameter.
 */
export const SOLVER_MODEL_DEFAULT = {
	provider: "kimi-coding",
	id: "kimi-k2.6",
};

/**
 * Explicit fallback chain when the default is unreachable. Ordered by
 * preference. Each entry must be a stable agentic model that follows tool-use
 * contracts; nothing on this list is a code-completion-only model.
 */
export const SOLVER_MODEL_FALLBACKS = [
	{ provider: "anthropic", id: "claude-sonnet-4-6" },
	{ provider: "anthropic", id: "claude-opus-4-7" },
];

/**
 * Resolve which model should fill the solver role for the current run.
 *
 * @param {object} [preferences] - Operator preferences object. Only consulted
 *   for `preferences.autonomousSolver.model`. Anything else is ignored.
 * @returns {{ provider: string, id: string }} the selected solver model
 */
export function resolveSolverModel(preferences) {
	const override = preferences?.autonomousSolver?.model;
	if (override && typeof override === "object" && override.id) {
		return {
			provider: String(override.provider ?? SOLVER_MODEL_DEFAULT.provider),
			id: String(override.id),
		};
	}
	if (typeof override === "string" && override.trim()) {
		// Allow "provider/model" short form for ergonomics; default provider when
		// only a model id is supplied.
		const trimmed = override.trim();
		const slash = trimmed.indexOf("/");
		if (slash > 0) {
			return {
				provider: trimmed.slice(0, slash),
				id: trimmed.slice(slash + 1),
			};
		}
		return { provider: SOLVER_MODEL_DEFAULT.provider, id: trimmed };
	}
	return { ...SOLVER_MODEL_DEFAULT };
}

/**
 * Resolve the ordered candidate list for the solver role: primary first, then
 * the fallback chain. Callers iterate until they find a reachable provider.
 *
 * @param {object} [preferences]
 * @returns {Array<{ provider: string, id: string }>}
 */
export function resolveSolverModelCandidates(preferences) {
	const primary = resolveSolverModel(preferences);
	const candidates = [primary];
	for (const fallback of SOLVER_MODEL_FALLBACKS) {
		if (fallback.provider === primary.provider && fallback.id === primary.id) {
			continue;
		}
		candidates.push({ ...fallback });
	}
	return candidates;
}

/**
 * True if the supplied model would be selected as solver for these preferences.
 * Useful for invariants and tests.
 *
 * @param {{ provider?: string, id?: string }} model
 * @param {object} [preferences]
 * @returns {boolean}
 */
export function isSolverModel(model, preferences) {
	if (!model?.id) return false;
	const solver = resolveSolverModel(preferences);
	return (
		String(model.provider ?? solver.provider) === solver.provider &&
		String(model.id) === solver.id
	);
}
