import { v4 as uuidv4 } from 'uuid';
import { redisClient } from './redis.js';
import { logger } from './logger.js';

const EXPIRY_COUNTER = 10; // seconds
const HEARTBEAT_INTERVAL = 1; // seconds

/**
 * This function initializes the online user count feature by setting up an endpoint
 * that serves the current count of online users. The count is updated in real-time
 * using Server-Sent Events (SSE) and Redis pub/sub.
 * 
 * @param {express.Express} app - The Express application instance.
 * @returns {void}
 */
export function initOnlineUserCount(app) {
    app.ws('/api/online', async (ws, req) => {
        logger.info('New WS connection established');

        const getOnlineCount = async () => {
            const keys = await redisClient.keys('online:*');
            return keys.length;
        };

        async function publishOnlineCount() {
            const onlineCount = await getOnlineCount();
            await redisClient.publish('online_updates', onlineCount.toString());
        }

        let lastSentOnlineCount = null;
        const sendOnlineCount = async () => {
            const onlineCount = await getOnlineCount();

            if (onlineCount === lastSentOnlineCount) {
                return; // No change in count, no need to send
            }

            ws.send(onlineCount.toString());
        };

        // Generate a unique ID for this connection
        const connectionId = uuidv4();
        const redisKey = `online:${connectionId}`;

        // Add the connection to Redis with a 10-second expiration
        await redisClient.set(redisKey, '1', { EX: EXPIRY_COUNTER });

        // Notify other instances about the new connection
        await publishOnlineCount();

        // Periodically refresh the expiration time (heartbeat)
        const heartbeatInterval = setInterval(async () => {
            ws.ping();
            await redisClient.expire(redisKey, EXPIRY_COUNTER);
            await sendOnlineCount();
        }, HEARTBEAT_INTERVAL * 1000);

        // Send the initial count
        await sendOnlineCount();

        // Subscribe to Redis pub/sub for updates (optional)
        const subscriber = redisClient.duplicate();
        await subscriber.connect();
        await subscriber.subscribe('online_updates', async () => {
            await sendOnlineCount();
        });

        ws.on('close', async () => {
            logger.info('WebSocket connection closed');
            clearInterval(heartbeatInterval);
            await redisClient.del(redisKey); // Remove the connection key
            await publishOnlineCount(); // Notify other instances
            await subscriber.disconnect();
        });
    });
}

