import { HelperModel } from '../config/helper-model.js';
import { compositeScore, getQualityTier, getQualityTierFromScore, } from './model-benchmarks.js';
import { getProviderRuntimeSnapshot, getProviderUsageSnapshot, listProviderRuntimeSnapshots, } from './runtime-snapshot.js';
function cloneFavoritesData(data) {
    return {
        pinned: data.pinned.map((entry) => ({ ...entry })),
        history: data.history.map((entry) => ({ ...entry })),
    };
}
function findModelDefinition(models, modelRef) {
    return models.find((model) => model.registryKey === modelRef);
}
function toModelReference(model) {
    return {
        modelId: model.id,
        providerId: model.provider,
        registryKey: model.registryKey,
    };
}
function buildFavoriteIndexes(data) {
    return {
        pinnedByRegistryKey: new Map(data.pinned.map((entry) => [entry.registryKey, entry])),
        recentByRegistryKey: new Map(data.history.map((entry) => [entry.registryKey, entry])),
    };
}
function buildSyntheticBenchmarkRecord(model, syntheticInfo) {
    return {
        ...toModelReference(model),
        kind: 'synthetic',
        available: true,
        displayName: model.displayName,
        backendCount: syntheticInfo.backendCount,
        keyedBackendCount: syntheticInfo.keyedBackendCount,
        tier: syntheticInfo.tier,
        compositeScore: syntheticInfo.bestCompositeScore,
        ...(syntheticInfo.bestCompositeScore != null
            ? { qualityTier: getQualityTierFromScore(syntheticInfo.bestCompositeScore) }
            : {}),
    };
}
function buildCatalogBenchmarkRecord(model, benchmark) {
    return {
        ...toModelReference(model),
        kind: 'catalog',
        available: true,
        displayName: model.displayName,
        organization: benchmark.organization,
        sourceName: benchmark.name,
        benchmarks: benchmark.benchmarks,
        compositeScore: compositeScore(benchmark.benchmarks),
        qualityTier: getQualityTier(benchmark.benchmarks),
    };
}
function buildModelBenchmark(model, deps) {
    if (model.provider === 'synthetic') {
        const syntheticInfo = deps.providerRegistry.getSyntheticModelInfoFromCatalog(model.id);
        return syntheticInfo ? buildSyntheticBenchmarkRecord(model, syntheticInfo) : undefined;
    }
    const benchmark = deps.benchmarkStore.getBenchmarks(model.id)
        ?? deps.benchmarkStore.getBenchmarks(model.displayName);
    return benchmark ? buildCatalogBenchmarkRecord(model, benchmark) : undefined;
}
function buildModelRouting(model, deps) {
    if (model.provider === 'synthetic') {
        const syntheticInfo = deps.providerRegistry.getSyntheticModelInfoFromCatalog(model.id);
        return {
            kind: 'synthetic',
            failoverStrategy: 'intra-synthetic',
            ...(syntheticInfo
                ? {
                    synthetic: {
                        backendCount: syntheticInfo.backendCount,
                        keyedBackendCount: syntheticInfo.keyedBackendCount,
                        tier: syntheticInfo.tier,
                        bestCompositeScore: syntheticInfo.bestCompositeScore,
                    },
                }
                : {}),
        };
    }
    const alternative = deps.providerRegistry.findAlternativeModel(model.registryKey);
    if (!alternative) {
        return {
            kind: 'direct',
            failoverStrategy: 'none',
        };
    }
    return {
        kind: 'direct',
        failoverStrategy: alternative.provider === 'synthetic' ? 'synthetic-wrapper' : 'same-tier-provider',
        alternative: toModelReference(alternative),
    };
}
function buildModelRecord(model, currentModel, favorites, deps) {
    const indexes = buildFavoriteIndexes(favorites);
    const pinned = indexes.pinnedByRegistryKey.get(model.registryKey);
    const recent = indexes.recentByRegistryKey.get(model.registryKey);
    return {
        ...toModelReference(model),
        displayName: model.displayName,
        description: model.description,
        selectable: model.selectable,
        current: currentModel.registryKey === model.registryKey,
        capabilities: model.capabilities,
        contextWindow: model.contextWindow,
        ...(model.tier ? { tier: model.tier } : {}),
        ...(model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {}),
        favorite: {
            pinned: pinned != null,
            recent: recent != null,
            ...(pinned ? { pinnedAt: pinned.pinnedAt } : {}),
            ...(recent ? { lastUsed: recent.lastUsed, useCount: recent.count } : {}),
        },
        ...(buildModelBenchmark(model, deps) ? { benchmark: buildModelBenchmark(model, deps) } : {}),
        routing: buildModelRouting(model, deps),
    };
}
function buildFavoriteRecord(registryKey, models, extras) {
    const model = findModelDefinition(models, registryKey);
    return {
        registryKey,
        available: model != null,
        ...(model
            ? {
                modelId: model.id,
                providerId: model.provider,
                displayName: model.displayName,
            }
            : {}),
        ...extras,
    };
}
async function loadFavoritesSnapshot(deps) {
    const favorites = cloneFavoritesData(await deps.favoritesStore.load());
    const models = deps.providerRegistry.listModels();
    const pinned = favorites.pinned.map((entry) => buildFavoriteRecord(entry.registryKey, models, { pinnedAt: entry.pinnedAt }));
    const recent = favorites.history
        .slice()
        .sort((a, b) => b.lastUsed.localeCompare(a.lastUsed))
        .map((entry) => buildFavoriteRecord(entry.registryKey, models, {
        lastUsed: entry.lastUsed,
        useCount: entry.count,
    }));
    return { pinned, recent };
}
function applyModelQuery(models, query) {
    if (!query)
        return models;
    return models.filter((model) => {
        if (query.providerId && model.providerId !== query.providerId)
            return false;
        if (query.selectableOnly && !model.selectable)
            return false;
        if (query.favorites === 'pinned' && !model.favorite.pinned)
            return false;
        if (query.favorites === 'recent' && !model.favorite.recent)
            return false;
        return true;
    });
}
function requireProviderQualifiedRegistryKey(modelRef) {
    if (!modelRef.includes(':')) {
        throw new Error(`Model references must use a provider-qualified registryKey; received '${modelRef}'.`);
    }
}
function resolveModelOrThrow(deps, modelRef) {
    requireProviderQualifiedRegistryKey(modelRef);
    const models = deps.providerRegistry.listModels();
    const model = findModelDefinition(models, modelRef);
    if (!model) {
        throw new Error(`Model '${modelRef}' not found.`);
    }
    return model;
}
async function resolvePinnedRegistryKeyOrThrow(deps, modelRef) {
    requireProviderQualifiedRegistryKey(modelRef);
    const models = deps.providerRegistry.listModels();
    const model = findModelDefinition(models, modelRef);
    if (model)
        return model.registryKey;
    const favorites = cloneFavoritesData(await deps.favoritesStore.load());
    const pinned = favorites.pinned.find((entry) => entry.registryKey === modelRef);
    if (pinned)
        return pinned.registryKey;
    throw new Error(`Model '${modelRef}' not found.`);
}
async function buildBenchmarkRecords(deps, query) {
    const models = deps.providerRegistry.listModels();
    const selectedModels = query?.registryKeys
        ? query.registryKeys
            .map((registryKey) => {
            requireProviderQualifiedRegistryKey(registryKey);
            return findModelDefinition(models, registryKey);
        })
            .filter((model) => model != null)
        : models;
    const records = selectedModels
        .map((model) => buildModelBenchmark(model, deps))
        .filter((record) => record != null)
        .sort((a, b) => {
        const scoreA = a.compositeScore ?? -1;
        const scoreB = b.compositeScore ?? -1;
        if (scoreA !== scoreB)
            return scoreB - scoreA;
        return a.registryKey.localeCompare(b.registryKey);
    });
    return typeof query?.limit === 'number' ? records.slice(0, query.limit) : records;
}
function buildCatalogRefreshResult(deps) {
    const models = deps.providerRegistry.getCatalogModelDefinitions();
    return {
        modelCount: models.length,
        providerCount: new Set(models.map((model) => model.provider)).size,
    };
}
export function createProviderApi(deps) {
    return {
        listProviderIds() {
            return deps.providerRegistry
                .listProviders()
                .map((provider) => provider.name)
                .slice()
                .sort((a, b) => a.localeCompare(b));
        },
        async getCurrentModel() {
            const currentModel = deps.providerRegistry.getCurrentModel();
            const favorites = cloneFavoritesData(await deps.favoritesStore.load());
            return buildModelRecord(currentModel, currentModel, favorites, deps);
        },
        async listModels(query) {
            const currentModel = deps.providerRegistry.getCurrentModel();
            const favorites = cloneFavoritesData(await deps.favoritesStore.load());
            const models = deps.providerRegistry.listModels().map((model) => buildModelRecord(model, currentModel, favorites, deps));
            return applyModelQuery(models, query);
        },
        async selectModel(registryKey) {
            deps.providerRegistry.setCurrentModel(registryKey);
            return await this.getCurrentModel();
        },
        async registerDiscoveredProviders(servers) {
            deps.providerRegistry.registerDiscoveredProviders([...servers]);
        },
        async refreshCatalog() {
            await deps.providerRegistry.refreshCatalog();
            return buildCatalogRefreshResult(deps);
        },
        async refreshBenchmarks() {
            await deps.benchmarkStore.refreshBenchmarks();
            return (await buildBenchmarkRecords(deps)).length;
        },
        async refreshModelLimits() {
            return await deps.providerRegistry.refreshModelLimits();
        },
        async getFavorites() {
            return await loadFavoritesSnapshot(deps);
        },
        async pinModel(registryKey) {
            const model = resolveModelOrThrow(deps, registryKey);
            await deps.favoritesStore.pinModel(model.registryKey);
            return await loadFavoritesSnapshot(deps);
        },
        async unpinModel(registryKey) {
            const resolvedRegistryKey = await resolvePinnedRegistryKeyOrThrow(deps, registryKey);
            await deps.favoritesStore.unpinModel(resolvedRegistryKey);
            return await loadFavoritesSnapshot(deps);
        },
        async recordModelUsage(registryKey) {
            const model = resolveModelOrThrow(deps, registryKey);
            await deps.favoritesStore.recordUsage(model.registryKey);
            return await loadFavoritesSnapshot(deps);
        },
        async listBenchmarks(query) {
            return await buildBenchmarkRecords(deps, query);
        },
        async queryRuntimeMetadata(query) {
            if (query.scope === 'all') {
                return {
                    scope: 'all',
                    snapshots: await listProviderRuntimeSnapshots(deps.providerRegistry),
                };
            }
            if (query.scope === 'provider') {
                return {
                    scope: 'provider',
                    snapshot: await getProviderRuntimeSnapshot(deps.providerRegistry, query.providerId),
                };
            }
            return {
                scope: 'usage',
                snapshot: await getProviderUsageSnapshot(deps.providerRegistry, query.providerId),
            };
        },
        createHelperModel(configManager) {
            return new HelperModel({
                configManager,
                providerRegistry: deps.providerRegistry,
            });
        },
    };
}
