import { normalizeMatrixCellAvailability, probeCursorSubagentModel, resolveCursorModelCatalog, validateMatrixCell, } from './availability.js';
function errorDiagnostic(error) {
    return error instanceof Error ? error.message : String(error);
}
function joinDiagnostics(...diagnostics) {
    return diagnostics
        .map((diagnostic) => diagnostic?.trim() ?? '')
        .filter((diagnostic) => diagnostic.length > 0)
        .join('\n');
}
function availabilityRef(ref) {
    if (ref.value !== null) {
        return { provider: ref.provider, value: ref.value, target: null };
    }
    if (ref.target === null) {
        return null;
    }
    const value = ref.target.model ?? ref.target.effort;
    if (!value) {
        return null;
    }
    return {
        provider: ref.target.harness ?? ref.provider,
        value,
        target: ref.target,
    };
}
function oracleOptions(context, target) {
    return {
        cwd: context.options.cwd,
        ...(context.options.env ? { env: context.options.env } : {}),
        ...(context.options.dependencies
            ? { dependencies: context.options.dependencies }
            : {}),
        detailed: true,
        ...(target ? { target } : {}),
    };
}
function cursorCatalogDiagnostic(value, presence) {
    return presence
        ? `Cursor's broad model catalog lists '${value}', but subagent Task dispatch could not be validated.`
        : `Cursor's broad model catalog does not list '${value}'.`;
}
function resolveCursorCatalogOnce(context) {
    if (context.cursorCatalog === null) {
        const resolver = context.options.resolveCursorModelCatalog ?? resolveCursorModelCatalog;
        context.cursorCatalog = resolver(context.options).catch((error) => ({
            status: 'failed',
            candidates: [],
            sourceCommand: null,
            diagnostic: errorDiagnostic(error),
        }));
    }
    return context.cursorCatalog;
}
function probeCursorCandidateOnce(value, context) {
    const cached = context.cursorTaskProbes.get(value);
    if (cached) {
        return cached;
    }
    const probe = context.options.probeCursorSubagentModel ?? probeCursorSubagentModel;
    const pending = probe(value, context.options)
        .then((result) => ({ result, diagnostic: '' }))
        .catch((error) => ({
        result: {
            availability: 'unvalidated',
            decisive: false,
            evidence: 'none',
        },
        diagnostic: errorDiagnostic(error),
    }));
    context.cursorTaskProbes.set(value, pending);
    return pending;
}
async function validateCursorRef(ref, value, context) {
    const taskProbe = await probeCursorCandidateOnce(value, context);
    if (taskProbe.result.decisive) {
        return {
            ref,
            status: taskProbe.result.availability,
            evidence: taskProbe.result.evidence,
            catalogPresence: null,
            diagnostic: joinDiagnostics(taskProbe.diagnostic, taskProbe.result.message),
        };
    }
    const catalog = await resolveCursorCatalogOnce(context);
    if (catalog.status === 'resolved') {
        const catalogPresence = catalog.candidates.includes(value);
        return {
            ref,
            status: catalogPresence ? 'unvalidated' : 'unknown-value',
            evidence: 'catalog-only',
            catalogPresence,
            diagnostic: joinDiagnostics(taskProbe.diagnostic, cursorCatalogDiagnostic(value, catalogPresence)),
        };
    }
    return {
        ref,
        status: 'unvalidated',
        evidence: 'none',
        catalogPresence: null,
        diagnostic: joinDiagnostics(taskProbe.diagnostic, catalog.diagnostic),
    };
}
async function validateRef(ref, context) {
    const candidate = availabilityRef(ref);
    if (candidate === null) {
        return {
            ref,
            status: 'unvalidated',
            evidence: 'none',
            catalogPresence: null,
            diagnostic: 'No dispatch candidate value is available for validation.',
        };
    }
    if (candidate.provider.trim().toLowerCase() === 'cursor') {
        return validateCursorRef(ref, candidate.value, context);
    }
    const validator = context.options.validateMatrixCell ?? validateMatrixCell;
    try {
        const result = normalizeMatrixCellAvailability(await validator(candidate.provider, candidate.value, oracleOptions(context, candidate.target)));
        return {
            ref,
            status: result.availability,
            evidence: 'none',
            catalogPresence: null,
            diagnostic: result.message ?? '',
        };
    }
    catch (error) {
        return {
            ref,
            status: 'unvalidated',
            evidence: 'none',
            catalogPresence: null,
            diagnostic: errorDiagnostic(error),
        };
    }
}
export function createDispatchValidationPassContext(options = { cwd: process.cwd() }) {
    return {
        cursorCatalog: null,
        cursorTaskProbes: new Map(),
        options,
    };
}
export async function validateDispatchMatrixRefs(refs, context) {
    return Promise.all(refs.map((ref) => validateRef(ref, context)));
}
