/**
 * WebSocket Event System
 * Standardized event patterns for real-time communication
 */
import { createLogger } from "../core/index.js";
let logger; // Will be initialized when needed
function ensureLogger() {
    if (!logger) {
        logger = createLogger("WebSocketEvents");
    }
    return logger;
}
/**
 * Standard event types
 */
export var EventTypes;
(function (EventTypes) {
    // Connection events
    EventTypes["CONNECT"] = "connect";
    EventTypes["DISCONNECT"] = "disconnect";
    EventTypes["ERROR"] = "error";
    // Data events
    EventTypes["DATA_UPDATE"] = "data:update";
    EventTypes["DATA_CREATE"] = "data:create";
    EventTypes["DATA_DELETE"] = "data:delete";
    EventTypes["DATA_SYNC"] = "data:sync";
    // Status events
    EventTypes["STATUS_CHANGE"] = "status:change";
    EventTypes["STATUS_HEALTH"] = "status:health";
    EventTypes["STATUS_METRICS"] = "status:metrics";
    // Control events
    EventTypes["CONTROL_START"] = "control:start";
    EventTypes["CONTROL_STOP"] = "control:stop";
    EventTypes["CONTROL_RESTART"] = "control:restart";
    EventTypes["CONTROL_CONFIG"] = "control:config";
    // Subscription events
    EventTypes["SUBSCRIBE"] = "subscribe";
    EventTypes["UNSUBSCRIBE"] = "unsubscribe";
    // System events
    EventTypes["SYSTEM_PING"] = "system:ping";
    EventTypes["SYSTEM_PONG"] = "system:pong";
    EventTypes["SYSTEM_INFO"] = "system:info";
    EventTypes["SYSTEM_ALERT"] = "system:alert";
})(EventTypes || (EventTypes = {}));
/**
 * WebSocket Event Manager
 */
export class WebSocketEventManager {
    io;
    subscriptions = new Map();
    eventHandlers = new Map();
    constructor(io) {
        this.io = io;
        this.setupDefaultHandlers();
    }
    /**
     * Setup default event handlers
     */
    setupDefaultHandlers() {
        this.io.on("connection", (socket) => {
            ensureLogger().info(`Client connected: ${socket.id}`);
            // Handle ping/pong for keepalive
            socket.on(EventTypes.SYSTEM_PING, () => {
                socket.emit(EventTypes.SYSTEM_PONG, {
                    timestamp: new Date().toISOString(),
                    latency: 0,
                });
            });
            // Handle subscriptions
            socket.on(EventTypes.SUBSCRIBE, (channel) => {
                this.subscribe(socket, channel);
            });
            socket.on(EventTypes.UNSUBSCRIBE, (channel) => {
                this.unsubscribe(socket, channel);
            });
            // Handle disconnect
            socket.on(EventTypes.DISCONNECT, () => {
                ensureLogger().info(`Client disconnected: ${socket.id}`);
                this.cleanupSubscriptions(socket.id);
            });
            // Send initial connection info
            socket.emit(EventTypes.SYSTEM_INFO, {
                id: socket.id,
                timestamp: new Date().toISOString(),
                server: "framework-websocket",
                version: "1.0.0",
            });
        });
    }
    /**
     * Subscribe socket to a channel
     */
    subscribe(socket, channel) {
        socket.join(channel);
        if (!this.subscriptions.has(channel)) {
            this.subscriptions.set(channel, new Set());
        }
        this.subscriptions.get(channel).add(socket.id);
        ensureLogger().debug(`Socket ${socket.id} subscribed to ${channel}`);
        socket.emit(EventTypes.SUBSCRIBE, {
            success: true,
            channel,
            timestamp: new Date().toISOString(),
        });
    }
    /**
     * Unsubscribe socket from a channel
     */
    unsubscribe(socket, channel) {
        socket.leave(channel);
        const subs = this.subscriptions.get(channel);
        if (subs) {
            subs.delete(socket.id);
            if (subs.size === 0) {
                this.subscriptions.delete(channel);
            }
        }
        ensureLogger().debug(`Socket ${socket.id} unsubscribed from ${channel}`);
        socket.emit(EventTypes.UNSUBSCRIBE, {
            success: true,
            channel,
            timestamp: new Date().toISOString(),
        });
    }
    /**
     * Clean up all subscriptions for a socket
     */
    cleanupSubscriptions(socketId) {
        for (const [channel, subs] of this.subscriptions.entries()) {
            if (subs.has(socketId)) {
                subs.delete(socketId);
                if (subs.size === 0) {
                    this.subscriptions.delete(channel);
                }
            }
        }
    }
    /**
     * Emit event to all clients
     */
    broadcast(event, payload) {
        this.io.emit(event, payload);
        ensureLogger().debug(`Broadcast event: ${event}`);
    }
    /**
     * Emit event to specific room/channel
     */
    emit(channel, event, payload) {
        this.io.to(channel).emit(event, payload);
        ensureLogger().debug(`Emit to ${channel}: ${event}`);
    }
    /**
     * Send event to specific socket
     */
    send(socketId, event, payload) {
        this.io.to(socketId).emit(event, payload);
        ensureLogger().debug(`Send to ${socketId}: ${event}`);
    }
    /**
     * Register custom event handler
     */
    on(event, handler) {
        if (!this.eventHandlers.has(event)) {
            this.eventHandlers.set(event, new Set());
            // Register with socket.io
            this.io.on("connection", (socket) => {
                socket.on(event, (data) => {
                    const handlers = this.eventHandlers.get(event);
                    if (handlers) {
                        handlers.forEach((h) => h(socket, data));
                    }
                });
            });
        }
        this.eventHandlers.get(event).add(handler);
    }
    /**
     * Get subscription statistics
     */
    getStats() {
        const stats = {
            connections: this.io.sockets.sockets.size,
            channels: this.subscriptions.size,
            subscriptions: {},
        };
        for (const [channel, subs] of this.subscriptions.entries()) {
            stats.subscriptions[channel] = subs.size;
        }
        return stats;
    }
}
/**
 * Typed event emitter for specific domains
 */
export class TypedEventEmitter {
    manager;
    namespace;
    constructor(manager, namespace) {
        this.manager = manager;
        this.namespace = namespace;
    }
    /**
     * Emit typed event
     */
    emit(event, data) {
        const payload = {
            timestamp: new Date().toISOString(),
            type: String(event),
            source: this.namespace,
            data,
        };
        this.manager.broadcast(`${this.namespace}:${String(event)}`, payload);
    }
    /**
     * Emit to specific channel
     */
    emitTo(channel, event, data) {
        const payload = {
            timestamp: new Date().toISOString(),
            type: String(event),
            source: this.namespace,
            target: channel,
            data,
        };
        this.manager.emit(channel, `${this.namespace}:${String(event)}`, payload);
    }
}
/**
 * Create event patterns for common use cases
 */
export const EventPatterns = {
    /**
     * CRUD event pattern
     */
    crud: (namespace) => ({
        created: (data) => ({
            event: `${namespace}:created`,
            payload: { timestamp: new Date().toISOString(), type: "created", data },
        }),
        updated: (data) => ({
            event: `${namespace}:updated`,
            payload: { timestamp: new Date().toISOString(), type: "updated", data },
        }),
        deleted: (id) => ({
            event: `${namespace}:deleted`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "deleted",
                data: { id },
            },
        }),
        list: (data) => ({
            event: `${namespace}:list`,
            payload: { timestamp: new Date().toISOString(), type: "list", data },
        }),
    }),
    /**
     * Status event pattern
     */
    status: (namespace) => ({
        online: () => ({
            event: `${namespace}:online`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "online",
                data: { status: "online" },
            },
        }),
        offline: () => ({
            event: `${namespace}:offline`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "offline",
                data: { status: "offline" },
            },
        }),
        error: (error) => ({
            event: `${namespace}:error`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "error",
                data: { error },
            },
        }),
        health: (health) => ({
            event: `${namespace}:health`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "health",
                data: health,
            },
        }),
    }),
    /**
     * Data stream pattern
     */
    stream: (namespace) => ({
        start: () => ({
            event: `${namespace}:stream:start`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "stream:start",
                data: {},
            },
        }),
        data: (data) => ({
            event: `${namespace}:stream:data`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "stream:data",
                data,
            },
        }),
        end: () => ({
            event: `${namespace}:stream:end`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "stream:end",
                data: {},
            },
        }),
        error: (error) => ({
            event: `${namespace}:stream:error`,
            payload: {
                timestamp: new Date().toISOString(),
                type: "stream:error",
                data: { error },
            },
        }),
    }),
};
export default {
    WebSocketEventManager,
    TypedEventEmitter,
    EventTypes,
    EventPatterns,
};
//# sourceMappingURL=websocketEvents.js.map