/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024  Rainbownapkin and the TTN Community

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.*/

//local imports
const commandPreprocessor = require('./commandPreprocessor');
const loggerUtils = require('../../utils/loggerUtils');
const {userModel} = require('../../schemas/userSchema');

module.exports = class{
    constructor(server){
        this.server = server;
        this.commandPreprocessor = new commandPreprocessor(server, this)
    }

    defineListeners(socket){
        socket.on("chatMessage", (data) => {this.handleChat(socket, data)});
        socket.on("setFlair", (data) => {this.setFlair(socket, data)});
        socket.on("setHighLevel", (data) => {this.setHighLevel(socket, data)});
    }

    handleChat(socket, data){
        this.commandPreprocessor.preprocess(socket, data);
    }

    async setFlair(socket, data){
        var userDB = await userModel.findOne({user: socket.user.user});

        if(userDB){
            try{
                //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
                const flairDB = await userDB.setFlair(data.flair);

                //GetConnects across all channels
                const connections = this.server.getConnections(socket.user.user);

                //For each connection
                connections.forEach((conn) => {
                    conn.updateFlair(flairDB.name);
                });
            }catch(err){
                return loggerUtils.socketExceptionHandler(socket, err);
            }
        }
    }

    async setHighLevel(socket, data){
        var userDB = await userModel.findOne({user: socket.user.user});

        if(userDB){
            try{
                //Set high level
                userDB.highLevel = data.highLevel;
                //Save user DB Document
                await userDB.save();

                //GetConnects across all channels
                const connections = this.server.getConnections(socket.user.user);

                //For each connection
                connections.forEach((conn) => {
                    conn.updateHighLevel(userDB.highLevel);
                });
            }catch(err){
                return loggerUtils.socketExceptionHandler(socket, err);
            }
        }
    }

    relayUserChat(socket, msg, type, links){
        const user = this.server.getSocketInfo(socket);
        this.relayChat(user.user, user.flair, user.highLevel, msg, type, socket.chan, links)
    }

    relayChat(user, flair, highLevel, msg, type = 'chat', chan, links){
        this.server.io.in(chan).emit("chatMessage", {user, flair, highLevel, msg, type, links});
    }

    relayServerWisper(socket, user, flair, highLevel, msg, type, links){
        socket.emit("chatMessage", {user, flair, highLevel, msg, type, links});
    }

    relayGlobalChat(user, flair, highLevel, msg, type = 'chat', links){
        this.server.io.emit("chatMessage", {user, flair, highLevel, msg, type, links});
    }

    relayTokeCallout(msg, links){
        this.relayGlobalChat("Tokebot", "", '∞', msg, "toke", links);
    }

    relayTokeWhisper(socket, msg, links){
        this.relayServerWisper(socket, "Tokebot", "", '∞', msg, "tokewhisper", links);
    }

    relayGlobalTokeWhisper(msg, links){
        this.relayGlobalChat("Tokebot", "", '∞', msg, "tokewhisper", links);
    }

    relayServerAnnouncement(msg, links){
        this.relayGlobalChat("Server", "", '∞', msg, "announcement", links);
    }

    relayChannelAnnouncement(chan, msg, links){
        const activeChan = this.server.activeChannels.get(chan);

        //If channel isn't null
        if(activeChan != null){
            this.relayChat("Channel", "", '∞', msg, "announcement", chan, links);
        }
    }

    clearChat(chan, user){
        const activeChan = this.server.activeChannels.get(chan);

        //If channel isn't null
        if(activeChan != null){
            const target = activeChan.userList.get(user);

            //If no user was entered OR the user was found
            if(user == null || target != null){
                this.server.io.in(chan).emit("clearChat", {user});
            }
        }
    }
}