import { createReconnectManager } from './reconnect';
import { deserializeData } from './serialization';
/**
 * Generic EventStream (SSE) connection manager with automatic reconnection
 * and handler management.
 *
 * Framework-agnostic - can be used with React, Svelte, Vue, or vanilla JS.
 */
export class EventStreamManager {
    es;
    manualClose = false;
    pendingMessages = [];
    messageHandler;
    reconnectManager;
    callbacks;
    url;
    reconnectConfig;
    firstMessageReceived = false;
    constructor(options) {
        this.url = options.url;
        this.callbacks = options.callbacks || {};
        this.reconnectConfig = {
            threshold: options.reconnect?.threshold ?? 3,
            baseDelay: options.reconnect?.baseDelay ?? 500,
            factor: options.reconnect?.factor ?? 2,
            maxDelay: options.reconnect?.maxDelay ?? 30000,
            jitter: options.reconnect?.jitter ?? 250,
        };
    }
    /**
     * Connect to the EventStream server
     */
    connect() {
        if (this.manualClose)
            return;
        this.es = new EventSource(this.url);
        this.firstMessageReceived = false;
        this.es.onopen = () => {
            this.reconnectManager?.recordSuccess();
            this.callbacks.onConnect?.();
        };
        this.es.onerror = () => {
            const error = new Error('EventStream error');
            this.callbacks.onError?.(error);
            this.callbacks.onDisconnect?.();
            if (this.manualClose) {
                return;
            }
            const result = this.reconnectManager?.recordFailure();
            if (result?.scheduled) {
                // Close current connection before reconnecting
                if (this.es) {
                    this.es.onopen = null;
                    this.es.onerror = null;
                    this.es.onmessage = null;
                    this.es.close();
                }
                this.es = undefined;
            }
        };
        this.es.onmessage = (event) => {
            // Record success on first message (not just on open)
            if (!this.firstMessageReceived) {
                this.reconnectManager?.recordSuccess();
                this.firstMessageReceived = true;
            }
            const payload = deserializeData(event.data);
            // Call the registered message handler
            if (this.messageHandler) {
                this.messageHandler(payload);
            }
            else {
                // Buffer messages until a handler is set
                this.pendingMessages.push(payload);
            }
            // Also call the callback if provided
            this.callbacks.onMessage?.(payload);
        };
        // Setup reconnect manager
        if (!this.reconnectManager) {
            this.reconnectManager = createReconnectManager({
                onReconnect: () => this.connect(),
                threshold: this.reconnectConfig.threshold,
                baseDelay: this.reconnectConfig.baseDelay,
                factor: this.reconnectConfig.factor,
                maxDelay: this.reconnectConfig.maxDelay,
                jitter: this.reconnectConfig.jitter,
                enabled: () => !this.manualClose,
            });
        }
    }
    /**
     * Set the message handler.
     * Any buffered messages will be delivered immediately.
     */
    setMessageHandler(handler) {
        this.messageHandler = handler;
        // Flush pending messages
        this.pendingMessages.forEach(handler);
        this.pendingMessages = [];
    }
    /**
     * Get current state
     */
    getState() {
        return {
            isConnected: this.es?.readyState === EventSource.OPEN,
            error: null, // Error state managed externally via callbacks
            readyState: this.es?.readyState ?? EventSource.CLOSED,
        };
    }
    /**
     * Close the EventStream connection and cleanup
     */
    close() {
        this.manualClose = true;
        this.reconnectManager?.dispose();
        if (this.es) {
            this.es.onopen = null;
            this.es.onerror = null;
            this.es.onmessage = null;
            this.es.close();
        }
        this.es = undefined;
        this.messageHandler = undefined;
        this.pendingMessages = [];
        // Notify disconnect callback
        this.callbacks.onDisconnect?.();
    }
    /**
     * Dispose of the manager (alias for close)
     */
    dispose() {
        this.close();
    }
}
//# sourceMappingURL=eventstream-manager.js.map