import { createDefaultChatCapability, createDefaultEmbeddingCapability, isLikelyEmbeddingModelId, listCapabilities, } from "./capabilities.js";
import { ConfigInvalidError } from "@oscharko-dev/keiko-security/errors/gateway";
const COST_RANK = { low: 0, medium: 1, high: 2 };
function matches(capability, query) {
    if (capability.kind !== query.kind) {
        return false;
    }
    if (query.toolCalling === true && !capability.toolCalling) {
        return false;
    }
    if (query.structuredOutput === true && !capability.structuredOutput) {
        return false;
    }
    if (query.supportsImageInput === true && !capability.supportsImageInput) {
        return false;
    }
    if (query.minContextWindow !== undefined && capability.contextWindow < query.minContextWindow) {
        return false;
    }
    return true;
}
export function assertConfiguredModel(config, modelId) {
    if (!config.providers.some((provider) => provider.modelId === modelId)) {
        throw new ConfigInvalidError(`model '${modelId}' is not configured as a provider`);
    }
}
export function findConfiguredCapability(config, modelId) {
    return (config.capabilities?.find((capability) => capability.id === modelId) ??
        listCapabilities().find((capability) => capability.id === modelId) ??
        (config.providers.some((provider) => provider.modelId === modelId)
            ? isLikelyEmbeddingModelId(modelId)
                ? createDefaultEmbeddingCapability(modelId)
                : createDefaultChatCapability(modelId)
            : undefined));
}
export function listConfiguredCapabilities(config) {
    return config.providers
        .map((provider) => findConfiguredCapability(config, provider.modelId))
        .filter((capability) => capability !== undefined);
}
export function selectConfiguredModel(config, query) {
    let best;
    for (const capability of listConfiguredCapabilities(config)) {
        if (!matches(capability, query)) {
            continue;
        }
        if (best === undefined || COST_RANK[capability.costClass] < COST_RANK[best.costClass]) {
            best = capability;
        }
    }
    return best?.id;
}
