import { enrichModelEntries, groupEntriesByProvider } from './health-enrichment.js';
/**
 * ModelPickerDataProvider produces enriched model picker data snapshots.
 *
 * Usage:
 * ```ts
 * const provider = new ModelPickerDataProvider(models, healthState, modelState);
 * const unsub = provider.subscribe(() => {
 *   const data = provider.getSnapshot();
 *   // render data.entries or data.groups
 * });
 * // When health or model state changes:
 * provider.updateHealthState(newHealthState);
 * provider.updateModelState(newModelState);
 * // Cleanup:
 * unsub();
 * provider.dispose();
 * ```
 */
export class ModelPickerDataProvider {
    _models;
    _healthState;
    _modelState;
    _pinnedIds;
    _snapshot;
    benchmarkStore;
    providerRegistry;
    _subscribers = new Set();
    constructor(models, healthState, modelState, options) {
        this._models = models;
        this._healthState = healthState;
        this._modelState = modelState;
        this._pinnedIds = options.pinnedIds ?? new Set();
        this.benchmarkStore = options.benchmarkStore;
        this.providerRegistry = options.providerRegistry;
        this._snapshot = this._buildSnapshot();
    }
    /**
     * Return the current enriched model picker data snapshot.
     * This is updated synchronously when state changes via update methods.
     */
    getSnapshot() {
        return this._snapshot;
    }
    /**
     * Register a callback invoked whenever the snapshot changes.
     * @returns An unsubscribe function.
     */
    subscribe(callback) {
        this._subscribers.add(callback);
        return () => this._subscribers.delete(callback);
    }
    /**
     * Update the model list (e.g. after registry reload).
     * Triggers a snapshot rebuild and notifies subscribers.
     */
    updateModels(models) {
        this._models = models;
        this._rebuild();
    }
    /**
     * Update health state (e.g. on ProviderHealthDomainState change).
     * Triggers a snapshot rebuild and notifies subscribers.
     */
    updateHealthState(healthState) {
        this._healthState = healthState;
        this._rebuild();
    }
    /**
     * Update model domain state (e.g. on active model or fallback change).
     * Triggers a snapshot rebuild and notifies subscribers.
     */
    updateModelState(modelState) {
        this._modelState = modelState;
        this._rebuild();
    }
    /**
     * Update the pinned/favorites model registry-key set.
     * Triggers a snapshot rebuild and notifies subscribers.
     */
    updatePinnedIds(pinnedIds) {
        this._pinnedIds = pinnedIds;
        this._rebuild();
    }
    /**
     * Release all subscriber references.
     * Does not clear internal state — getSnapshot() remains usable after disposal.
     */
    dispose() {
        this._subscribers.clear();
    }
    // ── Private ────────────────────────────────────────────────────────────────
    _rebuild() {
        this._snapshot = this._buildSnapshot();
        this._notify();
    }
    _buildSnapshot() {
        const entries = enrichModelEntries(this._models, this._healthState, this._modelState, this._pinnedIds, this.benchmarkStore, this.providerRegistry);
        const groups = groupEntriesByProvider(entries);
        const degradedProviderIds = [];
        const unavailableProviderIds = [];
        for (const [id, record] of this._healthState.providers) {
            if (record.status === 'degraded' || record.status === 'rate_limited') {
                degradedProviderIds.push(id);
            }
            else if (record.status === 'unavailable' || record.status === 'auth_error') {
                unavailableProviderIds.push(id);
            }
        }
        return {
            entries,
            groups,
            degradedProviderIds,
            unavailableProviderIds,
            activeModelId: this._modelState.registryKey,
            snapshotAt: Date.now(),
        };
    }
    _notify() {
        for (const cb of this._subscribers) {
            try {
                cb();
            }
            catch {
                // Subscriber errors must not crash the provider.
            }
        }
    }
}
