# JSDoc: Source: utils/loggerUtils.js

# Source: utils/loggerUtils.js

    /*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/>.*/

    //Config
    const config = require('../../config.json');

    /**
     * Creates and returns a custom exception, tagged as a 'custom' exception, using the 'custom' boolean property.
     * This is used to denote that this error was generated on purpose, with a human readable message, that can be securely sent to the client.
     * Unexpected exceptions should only be logged internally, however, as they may contain sensitive data.
     *
     * @param {String} msg - Error message to send the client
     * @param {String} type - Error type to send back to the client
     * @returns {Error} The exception to smith
     */
    module.exports.exceptionSmith = function(msg, type){
            //Create the new error with the given message
            const exception = new Error(msg);

            //Set the error type
            exception.type = type;

            //Mark the error as a custom error
            exception.custom = true;

            //Return the error
            return exception;
    }

    /**
     * Main error handling function
     * @param {Express.Response} res - Response being sent out to the client who caused the issue
     * @param {String} msg - Error message to send the client
     * @param {String} type - Error type to send back to the client
     * @param {Number} status - HTTP(s) Status Code to send back to the client
     * @returns {Express.Response} If we have a usable Express Response object, return it back after it's been cashed
     */
    module.exports.errorHandler = function(res, msg, type = "Generic", status = 400){
            //Some controllers do things after sending headers, for those, we should remain silent
            if(!res.headersSent){
                    res.status(status);
                    return res.send({errors: [{type, msg, date: new Date()}]});
            }
    }

    /**
     * Handles local exceptions which where not directly created by user interaction
     * @param {Error} err - Exception to handle
     */
    module.exports.localExceptionHandler = function(err){
            //If we're being verbose
            if(config.verbose){
                    //Log the error
                    console.log(err)
            }
    }

    /**
     * Handles exceptions which where directly the fault of user action >:(
     * @param {Express.Response} res - Express Response object to bitch at
     * @param {Error} err - Error created by the jerk in question
     */
    module.exports.exceptionHandler = function(res, err){
            //If this is a self-made problem
            if(err.custom){
                    module.exports.errorHandler(res, err.message, err.type);
            }else{
                    //Locally handle the exception
                    module.exports.localExceptionHandler(err);

                    //if not yell at the browser for fucking up, and tell it what it did wrong.
                    module.exports.errorHandler(res, "An unexpected server crash was just prevented. You should probably report this to an admin.", "Caught Exception");
            }
    }

    /**
     * Basic error-handling for socket.io so we don't just silently swallow errors.
     * @param {Socket} socket - Socket error originated from
     * @param {String} msg - Error message to send the client
     * @param {String} type - Error type to send back to the client
     * @returns {Boolean} - Passthrough from socket.emit
     */
    module.exports.socketErrorHandler = function(socket, msg, type = "Generic"){
            return socket.emit("error", {errors: [{type, msg, date: new Date()}]});
    }

    /**
     * Generates error messages for simple errors generated by socket.io interaction
     * @param {Socket} socket - Socket error originated from
     * @param {Error} err - Error created by the jerk in question
     * @returns {Boolean} - Passthrough from socket.emit
     */
    module.exports.socketExceptionHandler = function(socket, err){
            //If this is a self made problem
            if(err.custom){
                    //yell at the browser for fucking up, and tell it what it did wrong.
                    return module.exports.socketErrorHandler(socket, err.message, err.type);
            }else{
                    //Locally handle the exception
                    module.exports.localExceptionHandler(err);

                    //if not yell at the browser for fucking up
                    return module.exports.socketErrorHandler(socket, "An unexpected server crash was just prevented. You should probably report this to an admin.", "Server");
            }
    }

    /**
     * Generates error messages and drops connection for critical errors caused by socket.io interaction
     * @param {Socket} socket - Socket error originated from
     * @param {Error} err - Error created by the jerk in question
     * @returns {Boolean} - Passthrough from socket.disconnect
     */
    module.exports.socketCriticalExceptionHandler = function(socket, err){
            //If this is a self made problem
            if(err.custom){
                    //yell at the browser for fucking up, and tell it what it did wrong.
                    socket.emit("kick", {type: "Disconnected", reason: `Server Error: ${err.message}`});
            }else{
                    //Locally handle the exception
                    module.exports.localExceptionHandler(err);

                    //yell at the browser for fucking up
                    socket.emit("kick", {type: "Disconnected", reason: "An unexpected server crash was just prevented. You should probably report this to an admin."});
            }
            return socket.disconnect();
    }

    /**
     * Prints warning text to server console
     * @param {String} string - String to print to console
     */
    module.exports.consoleWarn = function(string){
            console.warn('\x1b[31m\x1b[4m%s\x1b[0m',string);
    }

    /**
     * Basic error-handling middleware to ensure we're not dumping stack traces to the client, as that would be insecure
     * @param {Error} err - Error to handle
     * @param {Express.Request} req - Express Request
     * @param {Express.Response} res - Express Response
     * @param {Function} next - Next function in the Express middleware chain (Not that it's getting called XP)
     */
    module.exports.errorMiddleware = function(err, req, res, next){
            //Set generic error
            var reason = "Server Error";

            //If it's un-authorized
            if(err.status == 403){
                    reason = "Unauthorized"
            }

            module.exports.errorHandler(res, err.message, reason, err.status);
    }