/**
 * emits an event to all clients filtered by the given options
 * @param {string} namespace - only to the specified namespace
 * @param {string} room - emit only to the specified room (can be combined with namespace)
 * @param {string} eventName - the name of the event
 * @param {object} params - any parameters/data to send with the event
 */
exports.emit = function(options) {
    if (this.io) {
        options = this.parse(options);

        if (options.namespace) {
            if (options.room) {
                this.io.of(options.namespace).to(options.room).emit(options.eventName, options.params);
            } else {
                this.io.of(options.namespace).emit(options.eventName, options.params);
            }
        } else {
            if (options.room) {
                this.io.in(options.room).emit(options.eventName, options.params);
            } else {
                this.io.emit(options.eventName, options.params);
            }
        }
    }
};

/**
 * emit an event to all clients except the sender
 * @param {string} room - broadcast in a specific room
 * @param {string} eventName - the name of the event
 * @param {object} params - the parameters/data to send with the event
 */
exports.broadcast = function(options) {
    if (this.socket) {
        options = this.parse(options);

        if (options.room) {
            this.socket.to(options.room).emit(options.eventName, options.params);
        } else {
            this.socket.broadcast.emit(options.eventName, options.params);
        }
    }
};

/**
 * emit an event to client and wait for an answer
 * @param {string} room - broadcast in a specific room
 * @param {string} eventName - the name of the event
 * @param {object} params - the parameters/data to send with the event
 */
exports.request = function(options) {
    if (this.socket) {
        options = this.parse(options);

        return new Promise((resolve) => {
            this.socket.emit(options.eventName, options.params, resolve);
        });
    }

    return null;
};

/**
 * send a private meessage to a socket
 * @param {string} socketId - the socket id to send the message to
 * @param {string} eventName - the name of the event
 * @param {object} params - the parameters/data to send with the event
 */
exports.message = function(options) {
    if (this.io) {
        options = this.parse(options);

        this.io.to(options.socketId).emit(options.eventName, options.params);
    }
};

/**
 * special serverconnect refresh broadcast
 * @param {string} action - the action that require refresh
 */
exports.refresh = async function(options) {
    if (this.io) {
        options = this.parse(options);

        // Do we have a global redis client?
        if (global.redisClient) {
            try { // ignore any errors here
                let wsKeys = await global.redisClient.keys('ws:' + options.action + ':*');
                if (wsKeys.length) await global.redisClient.del(wsKeys);
                let scKeys = await global.redisClient.keys('erc:' + '/api/' + options.action + '*');
                if (scKeys.length) await global.redisClient.del(scKeys);
            } catch (e) {
                console.error(e);
            }
        }

        this.io.of('/api').emit(options.action, options.params);
    }
};

/**
 * let current client join a room
 * @param {string} room - the room to join
 */
exports.join = function(options) {
    if (this.socket) {
        this.socket.join(this.parse(options.room));
    }
};

/**
 * let current client leave a room
 * @param {string} room - the room to leave
 */
exports.leave = function(options) {
    if (this.socket) {
        this.socket.leave(this.parse(options.room));
    }
};

/**
 * get the socket id of the current client
 */
exports.identify = function(options) {
    return this.socket ? this.socket.id : null;
};

/**
 * get the rooms the current client has joined
 */
exports.rooms = function(options) {
    return this.socket ? Array.from(this.socket.rooms) : [];
};

/**
 * get all the rooms
 * @param {string} namespace - the namespace
 */
exports.allRooms = async function(options) {
    if (this.io) {
        let adapter = io.of(options.namespace || '/').adapter;

        if (typeof adapter.allRooms == 'function') {
            return Array.from(await adapter.allRooms());
        } else if (adapter.rooms) {
            return Array.from(adapter.rooms.keys());
        }
    }

    return [];
};

/**
 * get all the connected sockets
 * @param {string} namespace - the namespace
 * @param {string} room - return only clients in a specific room
 */
exports.allSockets = async function(options) {
    if (this.io) {
        options = this.parse(options);

        if (options.room) {
            return Array.from(await this.io.of(options.namespace || '/').in(options.room).allSockets());
        } else {
            return Array.from(await this.io.of(options.namespace || '/').allSockets());
        }
    }

    return [];
};

