const EventEmitter = require('events')
const debug = require('debug')('48hr-email:notification')
require('events').defaultMaxListeners = 50;

/**
 * Receives sign-ins from users and notifies them when new mails are available.
 */
class ClientNotification extends EventEmitter {
    constructor() {
        super();
        this.pendingNotifications = new Map(); // address -> count
        this.io = null;
        this.imapService = null;
        this.timerSyncInterval = null;
    }

    use(io) {
        this.io = io;
        io.on('connection', socket => {
            debug(`[SOCKET] New connection: id=${socket.id}`);
            socket.on('sign in', address => {
                debug(`[SOCKET] sign in received for address: ${address}, socket id: ${socket.id}`);
                this._signIn(socket, address.toLowerCase())
            });
            socket.on('disconnect', reason => {
                debug(`[SOCKET] Disconnected: id=${socket.id}, reason=${reason}`);
            });
        })
    }

    startTimerSync(imapService) {
        this.imapService = imapService;

        // Broadcast timer sync every second to all connected clients
        if (this.timerSyncInterval) {
            clearInterval(this.timerSyncInterval);
        }

        this.timerSyncInterval = setInterval(() => {
            const secondsRemaining = this.imapService.getSecondsUntilNextRefresh();
            if (secondsRemaining !== null && this.io) {
                // Broadcast to all connected clients
                this.io.emit('refresh-timer-sync', secondsRemaining);
            }
        }, 1000);

        debug('Started timer sync broadcasting');
    }

    _signIn(socket, address) {
        debug(`socketio signed in: ${address}`)

        const newMailListener = () => {
            debug(`${address} has new messages, sending notification`)
            socket.emit('new emails')
            debug(`socket.emit('new emails') sent to ${address}`)
        }

        this.on(address, newMailListener)

        // Deliver any pending notifications
        const pending = this.pendingNotifications.get(address) || 0;
        if (pending > 0) {
            debug(`Delivering ${pending} pending notifications to ${address}`);
            for (let i = 0; i < pending; i++) {
                socket.emit('new emails');
            }
            this.pendingNotifications.delete(address);
        }

        socket.on('disconnect', reason => {
            debug(`client disconnect: ${address} (${reason})`)
            this.removeListener(address, newMailListener)
        })
    }

    emit(address) {
        address = address.toLowerCase();
        const hadListeners = super.emit(address);
        if (!hadListeners) {
            // Queue notification for later delivery
            const prev = this.pendingNotifications.get(address) || 0;
            this.pendingNotifications.set(address, prev + 1);
            debug(`No listeners for ${address}, queued notification (${prev + 1} pending)`);
        }

        // Also emit a global stats-update event for stats page
        if (this.io) {
            this.io.emit('stats-update');
            debug('Emitted stats-update to all connected clients');
        }

        return hadListeners;
    }
}

module.exports = ClientNotification
