/**
 * WebSocket Plugin for Real-time Alerts
 * 
 * Broadcasts environment alerts to connected clients.
 */

import { FastifyInstance } from 'fastify';
import websocket from '@fastify/websocket';

interface AlertMessage {
    type: 'ALERT' | 'READING' | 'HEARTBEAT';
    data: any;
    timestamp: string;
}

// Connected clients (storing the raw WebSocket)
const clients: Map<string, any> = new Map();

export async function websocketPlugin(fastify: FastifyInstance) {
    await fastify.register(websocket);

    /**
     * WebSocket endpoint for real-time alerts
     */
    fastify.get('/api/ws/alerts', { websocket: true }, (connection, request) => {
        const clientId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;

        // Get the raw WebSocket from the SocketStream
        const socket = connection.socket;

        clients.set(clientId, socket);
        fastify.log.info(`WebSocket client connected: ${clientId}`);

        // Send welcome message
        socket.send(JSON.stringify({
            type: 'CONNECTED',
            clientId,
            timestamp: new Date().toISOString()
        }));

        socket.on('message', (message: Buffer) => {
            try {
                const data = JSON.parse(message.toString());

                // Handle ping/pong for keepalive
                if (data.type === 'PING') {
                    socket.send(JSON.stringify({ type: 'PONG', timestamp: new Date().toISOString() }));
                }
            } catch {
                // Ignore invalid messages
            }
        });

        socket.on('close', () => {
            clients.delete(clientId);
            fastify.log.info(`WebSocket client disconnected: ${clientId}`);
        });

        socket.on('error', (error: Error) => {
            fastify.log.error(`WebSocket error for ${clientId}: ${error.message}`);
            clients.delete(clientId);
        });
    });
}

/**
 * Broadcast an alert to all connected clients
 */
export function broadcastAlert(alert: any): void {
    const message: AlertMessage = {
        type: 'ALERT',
        data: alert,
        timestamp: new Date().toISOString()
    };

    const payload = JSON.stringify(message);

    clients.forEach((socket, clientId) => {
        try {
            if (socket.readyState === 1) { // OPEN
                socket.send(payload);
            }
        } catch (error) {
            console.error(`Failed to broadcast to ${clientId}:`, error);
        }
    });
}

/**
 * Broadcast a sensor reading update
 */
export function broadcastReading(reading: any): void {
    const message: AlertMessage = {
        type: 'READING',
        data: reading,
        timestamp: new Date().toISOString()
    };

    const payload = JSON.stringify(message);

    clients.forEach((socket, clientId) => {
        try {
            if (socket.readyState === 1) {
                socket.send(payload);
            }
        } catch (error) {
            console.error(`Failed to broadcast reading to ${clientId}:`, error);
        }
    });
}

/**
 * Get count of connected clients
 */
export function getConnectedClientCount(): number {
    return clients.size;
}
