import { Logger, NodeSingletons } from '../../../../../src/index.js';
const createFallbackEmitter = () => {
    const listeners = new Map();
    return {
        on(event, listener) {
            const set = listeners.get(event) ?? new Set();
            set.add(listener);
            listeners.set(event, set);
        },
        off(event, listener) {
            const set = listeners.get(event);
            if (!set)
                return;
            set.delete(listener);
            if (set.size === 0)
                listeners.delete(event);
        },
        emit(event, payload) {
            const set = listeners.get(event);
            if (!set)
                return false;
            for (const listener of set)
                listener(payload);
            return true;
        },
    };
};
// Internal state for singleton service
const EventEmitterCtor = NodeSingletons?.EventEmitter;
const emitter = typeof EventEmitterCtor === 'function' ? new EventEmitterCtor() : createFallbackEmitter();
emitter.setMaxListeners?.(Infinity);
let interval = null;
let subscribers = 0;
let currentSettings = null;
let currentBuildSnapshot = null;
const broadcastTelemetrySnapshot = async () => {
    try {
        if (subscribers <= 0 || !currentBuildSnapshot || !currentSettings)
            return;
        const snapshot = await currentBuildSnapshot();
        const payload = {
            type: 'snapshot',
            ts: new Date().toISOString(),
            ...snapshot,
        };
        emitter.emit('snapshot', payload);
    }
    catch (err) {
        Logger.error('TelemetryMonitoringService.broadcastSnapshot failed', err);
        emitter.emit('error', err);
    }
};
const startPolling = () => {
    if (interval || !currentSettings)
        return;
    Logger.debug('Starting TelemetryMonitoringService polling');
    // Initial fetch
    void broadcastTelemetrySnapshot();
    interval = setInterval(() => {
        void broadcastTelemetrySnapshot();
    }, currentSettings.refreshIntervalMs);
};
const stopPolling = () => {
    if (interval) {
        Logger.debug('Stopping TelemetryMonitoringService polling');
        clearInterval(interval);
        interval = null;
    }
};
export const TelemetryMonitoringService = Object.freeze({
    subscribe(callback) {
        emitter.on('snapshot', callback);
        subscribers++;
        if (subscribers === 1) {
            startPolling();
        }
    },
    unsubscribe(callback) {
        emitter.off('snapshot', callback);
        subscribers--;
        if (subscribers <= 0) {
            stopPolling();
            currentSettings = null;
            currentBuildSnapshot = null;
        }
    },
    startMonitoring(settings, buildSnapshot) {
        if (subscribers === 0) {
            currentSettings = settings;
            currentBuildSnapshot = buildSnapshot;
        }
    },
    stopMonitoring() {
        if (subscribers <= 0) {
            stopPolling();
            currentSettings = null;
            currentBuildSnapshot = null;
        }
    },
});
export const teleStream = async (res, settings, buildSnapshot) => {
    const raw = res.getRaw();
    raw.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache, no-transform',
        Connection: 'keep-alive',
        'X-Accel-Buffering': 'no',
    });
    let closed = false;
    const send = async (payload) => {
        try {
            raw.write(`data: ${JSON.stringify(payload)}\n\n`);
        }
        catch (err) {
            Logger.error('Telemetry SSE send failed', err);
        }
    };
    // Send hello immediately
    await send({ type: 'hello', ts: new Date().toISOString() });
    // Start monitoring with the singleton service
    TelemetryMonitoringService.startMonitoring(settings, buildSnapshot);
    // Subscribe to telemetry snapshots
    const onSnapshot = (data) => {
        if (!closed) {
            void send(data);
        }
    };
    TelemetryMonitoringService.subscribe(onSnapshot);
    // Heartbeat to keep connection alive
    const hb = setInterval(() => {
        if (!closed)
            raw.write(': ping\n\n');
    }, 15000);
    raw.on('close', () => {
        closed = true;
        clearInterval(hb);
        TelemetryMonitoringService.unsubscribe(onSnapshot);
        TelemetryMonitoringService.stopMonitoring();
    });
};
