const axios = require('axios');
module.exports = Self => {
    Self.remoteMethodCtx('sendQueued', {
        description: 'Send a RocketChat message',
        accessType: 'WRITE',
        accepts: [],
        returns: {
            type: 'object',
            root: true
        },
        http: {
            path: `/sendQueued`,
            verb: 'POST'
        }
    });

    Self.sendQueued = async() => {
        const models = Self.app.models;
        const maxAttempts = 3;
        const sentStatus = 1;
        const errorStatus = 2;

        const chats = await models.Chat.find({
            where: {
                status: {neq: sentStatus},
                attempts: {lt: maxAttempts}
            }
        });

        for (let chat of chats) {
            if (chat.checkUserStatus) {
                try {
                    await Self.sendCheckingUserStatus(chat);
                    await updateChat(chat, sentStatus);
                } catch (error) {
                    await updateChat(chat, errorStatus, error);
                }
            } else {
                try {
                    await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
                    await updateChat(chat, sentStatus);
                } catch (error) {
                    await updateChat(chat, errorStatus, error);
                }
            }
        }
    };

    /**
     * Check user status in Rocket
     *
     * @param {object} chat - The sender id
     * @return {Promise} - The request promise
     */
    Self.sendCheckingUserStatus = async function sendCheckingUserStatus(chat) {
        const models = Self.app.models;

        const recipientName = chat.recipient.slice(1);
        const recipient = await models.Account.findOne({
            where: {
                name: recipientName
            }
        });

        const {data} = await Self.getUserStatus(recipient.name);
        if (data) {
            if (data.status === 'offline' || data.status === 'busy') {
                // Send message to department room
                const workerDepartment = await models.WorkerDepartment.findById(recipient.id, {
                    include: {
                        relation: 'department'
                    }
                });
                const department = workerDepartment && workerDepartment.department();
                const channelName = department && department.chatName;

                if (channelName)
                    return Self.sendMessage(chat.senderFk, `#${channelName}`, `@${recipient.name} ➔ ${chat.message}`);
                else
                    return Self.sendMessage(chat.senderFk, `@${recipient.name}`, chat.message);
            } else
                return Self.sendMessage(chat.senderFk, `@${recipient.name}`, chat.message);
        }
    };

    /**
     * Send a rocket message
     *
     * @param {object} senderFk - The sender id
     * @param {string} recipient - The user (@) or channel (#) to send the message
     * @param {string} message - The message to send
     * @return {Promise} - The request promise
     */
    Self.sendMessage = async function sendMessage(senderFk, recipient, message) {
        if (process.env.NODE_ENV !== 'production') {
            return new Promise(resolve => {
                return resolve({
                    statusCode: 200,
                    message: 'Fake notification sent'
                });
            });
        }

        const models = Self.app.models;
        const sender = await models.Account.findById(senderFk);

        const login = await Self.getServiceAuth();
        const avatar = `${login.host}/avatar/${sender.name}`;

        const options = {
            headers: {
                'X-Auth-Token': login.auth.token,
                'X-User-Id': login.auth.userId
            },
        };

        return axios.post(`${login.api}/chat.postMessage`, {
            'channel': recipient,
            'avatar': avatar,
            'alias': sender.nickname,
            'text': message
        }, options);
    };

    /**
     * Update status and attempts of a chat
     *
     * @param {object} chat - The chat
     * @param {string} status - The new status
     * @param {string} error - The error
     * @return {Promise} - The request promise
     */
    async function updateChat(chat, status, error) {
        return chat.updateAttributes({
            status: status,
            attempts: ++chat.attempts,
            error: error
        });
    }

    /**
     * Returns the current user status on Rocketchat
     *
     * @param {string} username - The recipient user name
     * @return {Promise} - The request promise
     */
    Self.getUserStatus = async function getUserStatus(username) {
        if (process.env.NODE_ENV !== 'production') {
            return new Promise(resolve => {
                return resolve({
                    data: {
                        status: 'online'
                    }
                });
            });
        }

        const login = await Self.getServiceAuth();

        const options = {
            params: {username},
            headers: {
                'X-Auth-Token': login.auth.token,
                'X-User-Id': login.auth.userId
            },
        };

        return axios.get(`${login.api}/users.getStatus`, options);
    };
};