import { alertNotificationService } from '../../monitoring/services/alert-notification-service.js';
const DEFAULT_HEALTH_SAMPLE = 'System health check';
function now() {
    return new Date();
}
export class ModelAvailabilityService {
    resolveProvider;
    resolvePriority;
    lastStatus = new Map();
    subscribers = new Set();
    constructor(resolveProvider, resolvePriority) {
        this.resolveProvider = resolveProvider;
        this.resolvePriority = resolvePriority;
    }
    async checkProviderHealth(provider, options = {}) {
        const sample = options.sampleText ?? DEFAULT_HEALTH_SAMPLE;
        const startedAt = Date.now();
        const previousStatus = this.lastStatus.get(provider);
        try {
            const service = this.resolveProvider(provider);
            if (!service || !service.isAvailable()) {
                throw new Error('Provider unavailable or not registered');
            }
            const timeout = options.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : undefined;
            if (timeout) {
                await Promise.race([
                    service.generateEmbedding(sample),
                    new Promise((_, reject) => setTimeout(() => reject(new Error('Health check timeout')), timeout))
                ]);
            }
            else {
                await service.generateEmbedding(sample);
            }
            const status = {
                provider,
                state: 'available',
                latencyMs: Date.now() - startedAt,
                lastCheckedAt: now()
            };
            this.lastStatus.set(provider, status);
            options.onProgress?.(status);
            this.broadcast(status);
            if (!previousStatus || previousStatus.state !== status.state) {
                alertNotificationService.emitAlert({
                    id: `provider-${provider}-${Date.now()}`,
                    source: 'model-availability',
                    severity: 'info',
                    message: `${provider} provider is available`,
                    metadata: {
                        provider,
                        state: status.state,
                        previousState: previousStatus?.state ?? 'unknown',
                        latencyMs: status.latencyMs
                    }
                });
            }
            return status;
        }
        catch (error) {
            const status = {
                provider,
                state: 'unavailable',
                lastCheckedAt: now(),
                message: error instanceof Error ? error.message : 'Unknown error'
            };
            this.lastStatus.set(provider, status);
            options.onProgress?.(status);
            this.broadcast(status);
            if (!previousStatus || previousStatus.state !== status.state) {
                alertNotificationService.emitAlert({
                    id: `provider-${provider}-${Date.now()}`,
                    source: 'model-availability',
                    severity: 'warning',
                    message: `${provider} provider became unavailable` + (status.message ? `: ${status.message}` : ''),
                    metadata: {
                        provider,
                        state: status.state,
                        previousState: previousStatus?.state ?? 'unknown'
                    }
                });
            }
            return status;
        }
    }
    getLastStatus(provider) {
        return this.lastStatus.get(provider);
    }
    getAllStatuses() {
        return Array.from(this.lastStatus.values()).sort((a, b) => a.provider.localeCompare(b.provider));
    }
    subscribe(listener) {
        this.subscribers.add(listener);
        this.getAllStatuses().forEach(status => listener(status));
        return () => {
            this.subscribers.delete(listener);
        };
    }
    async selectBestProvider(preferredProvider, options = {}) {
        const attempted = [];
        const orderedProviders = preferredProvider !== undefined
            ? [preferredProvider, ...this.getPriorityList().filter(p => p !== preferredProvider)]
            : this.getPriorityList();
        if (orderedProviders.length === 0) {
            return {
                selectedProvider: preferredProvider ?? 'minilm',
                reason: 'no-registered-providers',
                attemptedProviders: []
            };
        }
        for (const provider of orderedProviders) {
            const status = await this.checkProviderHealth(provider, options);
            attempted.push({
                provider,
                state: status.state,
                error: status.state === 'unavailable' ? status.message : undefined
            });
            if (status.state === 'available') {
                return {
                    selectedProvider: provider,
                    reason: options.onProgress ? 'health-check-success' : 'default',
                    attemptedProviders: attempted
                };
            }
        }
        return {
            selectedProvider: orderedProviders[0] ?? preferredProvider ?? 'minilm',
            reason: 'fallback-failed',
            attemptedProviders: attempted
        };
    }
    getPriorityList() {
        return this.resolvePriority();
    }
    broadcast(status) {
        for (const subscriber of this.subscribers) {
            subscriber(status);
        }
    }
}
//# sourceMappingURL=model-availability-service.js.map