/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2025 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 includes
const server = require('../server');
const {userModel} = require('../schemas/user/userSchema');

//User activity map to keep us from constantly reading off of the DB
let activityMap = new Map();

//How much difference between last write and now until we hit the DB again (in millis)
//Defaults to two minutes
const tolerance = 2 * (60 * 1000);
//How long a user has to be in-active to be considered offline
//Defaults to five minutes
const offlineTimeout = 5 * (60 * 1000);

module.exports.getPresence = async function(user, userDB){
    //If we don't have a user
    if(user == null || user == '' || user == 'Tokebot'){
        //Drop that shit
        return;
    }

    //Set status as offline
    let status = "Offline"
    //Attempt to pull from activity map to save on DB pull
    let activity = activityMap.get(user);
    //Pull current epoch in millis
    const now = new Date().getTime();

    //If we couldn't find anything in RAM
    if(activity == null){
        //If we wheren't handed a free user doc
        if(userDB == null){
            //Pull one from the username
            userDB = await userModel.findOne({user: user});
        }

        //If for some reason we can't find a user doc
        if(userDB == null){
            //Bail with empty status object
            return {
                status,
                activeConnections: [],
                lastActive: 0
            }
        }

        //Pull last active date from userDB
        activity = userDB.lastActive.getTime();
    }

    //Pull active connections for user from the channel manager
    const activeConnections = server.channelManager.getConnections(user);

    //If the user is connected to at least one channel
    if(activeConnections != null && activeConnections.length > 0){
        status = "Streaming";
    //Otherwise, if it's been five minutes
    }else if(now - activity < offlineTimeout){
        status = "Recently Active";
    }

    //Assemble and return status object
    return {
        status,
        activeConnections,
        lastActive: activity
    }
}

module.exports.presenceMiddleware = function(req, res, next){
    //Pull user from session
    const user = req.session.user;

    //if we have a user object
    if(user != null){
        //Handle Presence
        module.exports.handlePresence(user.user);
    }

    //Go on to next part of the middleware chain
    next();
}

module.exports.handlePresence = async function(user, userDB, noSave = false){
    //If we don't have a user
    if(user == null || user == ''){
        //Drop that shit
        return;
    }

    //Get current date as epoch (millis)
    const now = new Date();
    const millis = now.getTime();

    //Check last user activity
    const activity = activityMap.get(user);

    //If we have no recorded activity, or if the the time between now and the last activity is greater than two minutes
    if(activity == null || millis - activity > tolerance){
        //Set last user activity 
        activityMap.set(user, millis);

        //If we wheren't handed a free user doc
        if(userDB == null){
            //Pull one from the username
            userDB = await userModel.findOne({user: user});
        }

        //Set last active in user's DB document
        userDB.lastActive = now;

        //If saving is enabled
        if(!noSave){
            //Save document to 
            await userDB.save();
        }
    }
}