/**
 * Roll a die or multiple dice.
 * <pre>
 *      This command will roll dice and return the results. A few flows to consider:
 *      - number of dice and the number of dice faces delimited on a 'd'
 *          - delimiter can be capital or lower case;
 *      - multiple dice delimited by a space( ), comma(,), or plus sign(+)
 *      - space delimiting different dice rolls
 *      - multiple types of dice
 *      - multiple dice in roll
 *      - combinations of above
 * <pre>
 * Example Usage and Results:
 * <table style="width:30%;">
 *  <tr><td>Roll Argument(s)</td><td>Result Range</td><td>Example Output</td></tr>
 *  <tr><td>1d6</td><td>number between 1 and 6</td><td>4</td></tr>
 *  <tr><td>2d6</td><td>number between 2 and 12</td><td>6 = 4 + 2</td></tr>
 *  <tr><td>1d6 + 1d4</td><td>number between 2 and 10</td><td>4 = 1 + 3</td></tr>
 * </table> 
 * @module roll 
 * @param {...string} dice  - which dice (number of dice and/or type of dice) to roll; required
 * @return {string} - dice results (as a message to discord text channel)
 */
 module.exports = {
    name: 'roll',
    description: 'Roll a die or multiple dice!',
    aliases: ['dice'],
    usage: '#dType, ex: 1d6, 2d8, 1d6 + 1d12, 1d4+1d6, 1d4 1d12',
    args: true,
    cooldown: 0.1,
    /**
     * @method execute
     * @param {string} message - command, used to determine which channel to return results
     * @param {string} args - dice roll passed into arguments
     * @return {string} total of the die or dice rolled (includes each die roll if multiple dice requested) 
     */
    execute(message,args) {   
        /** 
         * @var {integer} dieTotal  
         * @summary total die roll, starting at 0 and incremented up based on die roll
         */
        let dieTotal = 0;
        /**
         * @var {string[]} dieArray 
         * @summary where we will prep and store the dice roll 
         */
        let dieArray = [];
        /**
         * @var {integer[]} diceArray
         * @summary results of each dice result for additional info in the roll 
         */
        let diceArray = [];
        /**
         * @var {string[]} userRoll
         * @summary the user input for the roll command, empty array if undefined
         */
        let userRoll =  args !== undefined ? args : []; 
        /**
         * * check if its one argument (no spaces) and has a plus (multiple dice)
         * if 0 args, program will fail since args are requires
         * if 1 arg, check if its a 1 dice roll or multipled dice without whitespace
         * if it is missing spaces, tell the user and exit the function early
         */
        if (userRoll.length === 1 && userRoll[0].indexOf('+') > -1) {
            userRoll = userRoll[0].split('+');
        }        
        if (userRoll.length === 1 && userRoll[0].indexOf(',') > -1) {
            userRoll = userRoll[0].split(',');
        }        
        // grab the raw input and remove bad array values/split them/etc.
        for (let i = 0; i < userRoll.length; i++) {
            let roll = userRoll[i].toLowerCase().split('d');
            if (!roll.includes('+')) {
                dieArray.push(roll);
            }
        }
        // roll each set of dice and then increment our total based on the results
        for (let j = 0; j < dieArray.length; j++) {
            /**
             * Roll each die independently, i.e. a 2d12 can be (1-12) + (1-12), not 2 * (1-12)
             *! NOTE: I am absolutely not a fan of a nested for loop method, but I want to ensure each die is rolled independently
             * Unless someone is rolling an absolutely insane amount of similar dice AND 
             * multiple types of dice combos, it shouldn't even be noticeable
             */
            for (let k = 0; k < parseInt(dieArray[j][0]); k++) {
                let roll = Math.ceil(Math.random() * parseInt(dieArray[j][1]));
                diceArray.push(roll);
                dieTotal += roll;
            }
        }
        /**
         * Clean up the final results and return them in a message
         *! Note: We add each die roll into the string if multiple are called in order to provide transparency in the rolls 
         */
        let total = "";
        if (diceArray.length <= 1) {
            total = '> ' + dieTotal.toString();
        } else {
            total = '> ' + dieTotal.toString() + ' = ' + diceArray.join(' + ');
        }
        if ((!total.includes("NaN") && !total.includes("> 0"))) {       // strings parse to 0 above, so this catches it as an error
            message.channel.send(total);
        } else {
            let reply = `You haven't used the roll command correctly, ${message.author}!`;
            reply += `\nThe correct usage looks like ${module.exports.usage}`;
            message.channel.send(reply);
        }
    }
};