// Invite Link

// ./codes/bf.js
// ./codes/getsrc.js
// ./codes/src.js
// ./codes/twitter.js
// ./codes/status.json (bot statuses)
// ./codes/filesetup.js
// ./codes/kb2cb.py
// ./codes/bash.js
// ./codes/runcode.js
// ./codes/cpp.js

// ./main.sh

Object.prototype.keys = function() {
  return Object.keys(this);
} //to make my life easier although I have yet to use it
require('dotenv').config();
const fetch = require('node-fetch');
const express = require('express');
const app = express();
const port = 3000;
const prefix = "kb!";
const https = require('https');
const Discord = require('discord.js');
// const Canvas = require('canvas'); // not working
const fs = require('fs');
const moment = require('moment');
const ytdl = require('ytdl-core');
const TwitterFetcher = require("./codes/twitter.js");
const cpp = require("./codes/cpp.js");
const rc = require("./codes/runcode.js");
const getsrc = require('./codes/getsrc.js');
const BrainFParser = require("./codes/bf.js");
const runBash = require("./codes/bash.js");
const childprocess = require("child_process");
const {popen} = require("./codes/popen.node"); //for executing shell commands bc I like synchronicity
function makeEmbed(input, title) {
  const embed = new Discord.MessageEmbed();
  embed.setColor('#00ff00');
  embed.setAuthor('Komali Bot 2', client.user.avatarURL());
  embed.setDescription(input.replace(/>>/g, '    '));
  if (title) embed.setTitle(title);
  return embed;
}
//trusted users that won't abuse the token (hopefully); these can use kb!codeblock 
var cmdUsers = [
  "327879060443234314", //Komali
  "454356237614841870", //Lior
  "264117376394592257", //Xeryph
  "550820095048548372", //HairyOtter07 
  "658861212657909791", //LieutenantPeriwinkle
  "149744576091914240", //AngryDemonNoises
  "692084258944057414", //CaptainShibe
  "304430648796381186", //Savage13
  "554012483967254559", //iTNTPiston
  "659901334266576926", //Cinnnamon
  "691457284718592042"  //BingsF
]
let fileSetup = require('./filesetup/filesetup.js');
fileSetup(fs, app, express, fetch, cmdUsers, __dirname);
var serverapp = app.listen(port, () => console.log(`(js) Web Server Running on Port ${port}`));
const io = require('socket.io').listen(serverapp);
io.on('connect', socket => {
  console.log("someone is on");
  socket.on('login', data => {
    console.log(data);
  });
});


let ReplacementString = "";
for(i=32;i<255;i++) if(i<128 || i > 160) ReplacementString+=(String.fromCharCode(i));
ReplacementString = ReplacementString.replace(/[\\\n\x7F *_~\`<:]/g,"").substring(20, 120);

function CompressUrl(url) { try {
  if(!url.startsWith("https:") || !(url.includes("cdn.discordapp") || url.includes("media.discordapp"))) return "Bad URL"
  url = url.split("/");
  if(url.length != 7) return "Bad URL"; 
  let c = url[4];
  let m = url[5];
  let str = "";
  for(i in c.split``) {
    str+= ReplacementString[parseInt(c[i]+m[i])]
  }
  return str + url[6];
} catch (e) { return e } }
function UncompressUrl(url) { try {
  let str = url.substring(0, 18);
  let f = url.substring(18, url.length);
  let tempc = ""
  let tempm = ""
  for(c in str.split``) {
    let ind = ReplacementString.indexOf(str[c]).toString()
    ind = ("0"+ind).slice(-2)
    tempc += ind.split``[0]
    tempm += ind.split``[1]
  }
  return "https://cdn.discordapp.com/attachments/" + tempc + "/" + tempm + "/" + f
} catch (e) { return e } }

const TEMPSTDOUT = process.stdout.write;
const TEMPSTDERR = process.stderr.write;


const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] });
const auth = require('./auth2.json');
client.commands = new Discord.Collection();
// Canvas.registerFont('./fonts/HyliaSerifBeta-Regular.otf', {
//   family: 'Hylia Serif'
// })
// Canvas.registerFont('./fonts/Sheikah-Sheikah Writing.otf', {
//   family: 'Sheikah'
// })
const activities_list = require("./codes/status.json"); //better it here than in ./jsons
client.on('ready', () => {
  setStatus();
  
  function setStatus() {
    const index = Math.floor(Math.random() * (activities_list.length - 1) + 1);
    client.user.setStatus("idle");
    client.user.setActivity(activities_list[index], {
      type: "WATCHING"
      // url: "https://www.twitch.tv/komali09" //if we want streaming
    });
  }
  setInterval(() => {
    setStatus();
  }, 300000); //3600000 for 1h, 900000 for 15m
  console.log(`(js) Logged in as ${client.user.tag}!`);

  fs.writeFileSync("./log.txt", "");
});

function hasPing(msg) {
  return (/<@\d*>/.test(msg.content) || /<@!\d*>/.test(msg.content) || /<@&\d*>/.test(msg.content) || msg.content.includes("@everyone") || msg.content.includes("@here") || msg.mentions.members.first())
}

client.on('messageCreate', async message => {
  message.reply = (c, a = {}) => {
      a.content = c;
      a["message_reference"] = { "message_id": message.id };
      fetch(`https://discord.com/api/v8/channels/${message.channel.id}/messages`, {
        method: "POST",
        headers: {
          "Authorization": `Bot ${process.env.TOKEN}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify(a)
      })
    }
  var splitMessage = new Array(2);
  if (message.content.toLowerCase().startsWith("kb!")) {
    splitMessage = message.content.split(/kb!(.+)/i)[1].split(" ");
  }
  const {
    attachments,
    content,
    guild
  } = message;
  //beautifier.io making objects spread out :I
  if (message.channel.type != "dm") {
    var emojis = message.guild.emojis.cache.map(e => e.toString());
  }
  if (message.guild != null && (message.guild.id == "714713954349482004" != (message.channel.id == "715226878348230707"))) {
    return;
  }
  if (splitMessage[0] === "help") {
    var winchance;
    var emotelength;
    var gemotelength = client.emojis.cache.map(x => x.name).length;
    var gwinchance = (1 / (gemotelength * 3) * 100).toFixed(3) + "%";
    if (message.channel.type == "dm") {
      emotelength = 0;
      winchance = "0%";
    } else {
      emotelength = message.guild.emojis.cache.map(e => e.toString()).length;
      winchance = (1 / (emotelength * 3) * 100).toFixed(3) + "%";
      if (winchance == "Infinity%") {
        winchance = "No Emotes";
      }
    }
    var randCmd =
      "`kb!hi`/`kb!hello`: Makes the bot say hi\n`kb!bye`/`kb!goodbye`: Makes the bot say goodbye\n`kb!cheers`: Cheers!\n`kb!sd/kb!selfdestruct`: Initiates the self destruct sequence\n`kb!ytdl` (`kb!ytdl {url}`) Lets you download a youtube video\n`kb!clipdl` (`kb!clipdl {url}`) Lets you download a Twitch Clip\n`kb!twdl` (`kb!twdl {url}`) Lets you download a twitter clip (BETA)\n`kb!servers`: Lists the servers the bot is in\n`kb!randomize`: Randomizes a string\n`kb!ps`/`kb!pscs`/`kb!ptest`: Discord.js is better than Nitro\n`kb!hype`/`kb!yay`: POGGERS\n`kb!egypt` (do kb!egypt help)\n`kb!widepeepo`: big pog\n`kb!c`/`kb!compress`: Compresses a `cdn.discordapp.com` link\n`kb!u`/`kb!uncompress`: Uncompresses said compressed url";

    var slotCmd =
      "`kb!slots`: Spin to Win\n`kb!ultraslots`: slots but it uses all the emotes the bot has access to\n`kb!minislots`: slots but it's cute\n`kb!megaslots`: slots but fat" +
      "\n\nEmotes in this server: " + emotelength + "\nAll emotes bot has access to: " + gemotelength + "\nSlots win chance (3): " + winchance +
      "\nUltraslots win chance (3): " + gwinchance;
    var devCmd =
      "`kb!emote`: use any emote from servers the bot is in (do kb!emote help)\n`kb!userinfo` (`kb!userinfo {user ping}`): Lists info about a user\n`kb!twitchapi` (`kb!twitchapi {user/game/stream/get/query} {user\'s name/game name/twitch api url/query}`) Accesses the twitch api so Komali doesn't have to make a new nodejs file every time he wants to test stuff \:\/\n\n`kb!codeblock`: https://komali-bot-2.komali09.repl.co/codeblock";
    var defaultCmd = "`kb!help random`\n`kb!help slots`\n`kb!help dev`\n`kb!help botw`\n`kb!credits`\n\nSource code: https://komali-bot-2.komali09.repl.co";
    var botwCmd = "`kb!randomshrine`: States a random IL shrine\n`kb!shrineinfo {shrine}`: Lists info about a shrine\n`kb!ilwr` (`kb!ilwr {shrine name} {any/nmg/100}`): Lists the IL wr for a shrine\n`kb!stats` (`kb!stats {weapon shield or bow}`): Lists the stats of a weapon, shield, or bow\n`kb!sheikah`/`kb!botw`: gives your text a cool font";
    var invite = "**Invite Link:**\nhttps://discord.com/api/oauth2/authorize?client_id=702572373261680796&permissions=8&scope=bot";
    var helps = {
      "default": `${defaultCmd}\n\n${invite}`,
      "random": randCmd,
      "slots": slotCmd,
      "dev": devCmd,
      "botw": botwCmd
    }
    var category = "Help Menu:";
    var hmenu = helps.default;
    if (Object.keys(helps).includes(splitMessage[1])) {
      category = splitMessage[1];
      hmenu = helps[category];
    }
    if (category !== "Help Menu:") {
      category = category.charAt(0).toUpperCase() + category.slice(1) + " Commands:";
    }
    const eembed = {
      "color": 0x00cc00,
      "title": "Komali Bot Commands:",
      fields: [{
        "name": category,
        "value": hmenu,
      }, ],
    }
    message.channel.send({
      embed: eembed
    });
  }
  if(splitMessage[0] == "credits") {
    message.channel.send("", {embed: {
  "color": 0x00ff00,
  "author": {
     "name": "Komali Bot 2",
     "icon_url": client.user.displayAvatarURL()
  },
   "title": "Bot Credits",
   "description": "**Prince Komali - Main Code**\n• Github: https://github.com/PrinceKomali\n• Twitch: https://twitch.tv/komali09\n• Youtube: https://youtube.com/c/KomaliPrinceOfRito\n\n**Lior - Python codeblock code and lots of ideas**\n• Github: https://github.com/Random-Fun\n• Twitch: https://twitch.tv/underscorelior\n• Youtube: https://youtube.com/c/underscorelior\n\n**HairyOtter07 - Lots of internal functions, BrainF Interpreter, and this command**\n• Github: https://github.com/HairyOtter07\n• Youtube: https://youtube.com/channel/UCoU5MpJGK_qv3tmwZbyeFGA\n\n**Other Contributers**:\n• LieutenantPeriwinkle\n• Xeryph\n• LordOfTheCube\n• happy_taco_dude\n• Puggietaur" 
}})
  }
  if (message.content === "kb!uptime") {
    let totalSeconds = (client.uptime / 1000);
    let days = Math.floor(totalSeconds / 86400);
    totalSeconds %= 86400;
    let hours = Math.floor(totalSeconds / 3600);
    totalSeconds %= 3600;
    let minutes = Math.floor(totalSeconds / 60);
    let seconds = Math.floor(totalSeconds % 60);
    let mili = client.uptime % 1000;
    message.channel.send(`Bot has been up for ${days} days, ${hours} hours, ${minutes} minutes and ${seconds}.${mili} seconds`);
  }
  if (splitMessage[0] == "rate") {
    if (!splitMessage[1]) {
      message.channel.send("No string provided!");
      return;
    }
    var msg = message.content.split(/ (.+)/)[1];
    let outmsg = msg;
    if (msg.length % 2 == 0) msg = msg.toLowerCase();
    if (msg.length % 2 == 1) msg = msg.toUpperCase();
    let komalibots = ["myself", "me", "komalibot", "komali bot", "komalibot 2", "komalibot2", "komali bot 2", "kb2"];
    if (komalibots.includes(msg.toLowerCase())) {
      message.channel.send(makeEmbed("I rate **myself** a 10.00/10"));
      return;
    }
    var charCodeNum = 0;
    for (i = 0; i < msg.length; i++) {
      charCodeNum += msg.charCodeAt(i);
    }
    var l = (msg.length);
    var num = charCodeNum * l;
    num = num % 1000;
    message.channel.send(makeEmbed("I rate **" + outmsg + "** a " + (num / 100)
      .toFixed(2) + "/10"));
  }
  if (splitMessage[0] == "shrine" || splitMessage[0] == "shrineinfo") {
    let s = require('./jsons/shrines.json');
    let item = message.content.split(/ (.+)/)[1];
    if (!item) {
      message.channel.send(makeEmbed('Usage: `kb!shrine {shrine name}`'));
      return;
    }
    var k = Object.keys(s).map(x => x.toLowerCase().replace(/'/g, ''));
    if (!k.includes(item.toLowerCase().replace(/'/g, ''))) {
      message.channel.send(makeEmbed('Invalid Query'));
      return;
    }
    var a = Object.entries(s).find(x => x[0].toLowerCase().replace(/'/g, '') == item.toLowerCase().replace(/'/g, ''));
    var cStr = [];
    var r = a[1].region;
    for (i = 0; i < Object.keys(a[1].chests).length; i++) {
      cStr.push('• ' + Object.values(a[1].chests)[i]);
    }
    var eCount = 0;
    var eStr = [];
    if (a[1].enemies == null) {
      eStr = '';
    } else {
      for (i = 0; i < Object.keys(a[1].enemies).length; i++) {
        eStr.push('• **' + Object.keys(a[1].enemies)[i] + '**: ' + Object.values(a[1].enemies)[i]);
        eCount += Object.values(a[1].enemies)[i];
      }
      eStr = '\n' + eStr.join('\n');
    }
    var e = makeEmbed(`**Region: ** ${r}\n**Chests**: ${cStr.length}\n${cStr.join('\n')}\n**Enemies: **${eCount + eStr}`, `${a[0]} (${a[1].puzzle_name.trim()})`);
    message.channel.send(e);
  }
  if (splitMessage[0] == "ilwr") {
    require('./codes/src.js').run(client, message, splitMessage, makeEmbed);
  }
  if (splitMessage[0] == "stats") {
    //Credit to HairyOtter07
    let w = require('./jsons/allWeapons.json');
    let item = message.content.split(/ (.+)/)[1];
    if (!item) {
      message.channel.send(makeEmbed('Usage: `/stats {weapon/bow/shield}`'));
      return;
    }
    var k = Object.keys(w).map(x => x.toLowerCase().replace(/'/g, ''));
    if (!k.includes(item.toLowerCase().replace(/'/g, ''))) {
      message.channel.send(makeEmbed('Invalid Query'));
      return;
    }
    var a = Object.entries(w).find( x => x[0].toLowerCase() .replace(/'/g, '') == item.toLowerCase() .replace(/'/g, '') );
    var c = Object.entries(a[1]);
    c.pop();
    for (var i in c) {
      c[i] = '**' + c[i][0] + ':** ' + c[i][1];
    }
    var e = makeEmbed('**Type: **' + a[1].type + '\n' + c.join('\n'), a[0]);
    message.channel.send(e);
  }
  if (splitMessage[0] == "randomshrine") {
    let s = require("./jsons/shrinenames.json");
    message.channel.send(s[Math.floor(Math.random() * s.length)]);
  }
  if (splitMessage[0] === "userinfo") {
    let user = message.mentions.users.first();
    var guilduser = message.guild.member(message.mentions.users.first());
    var userroles;
    if (guilduser.roles.cache.map(r => `${r}`).slice(0).reverse().join(' | ').toString().replace("@everyone | ", "").replace("@everyone", "") == "") {
      userroles = "No Roles";
    } else {
      userroles = guilduser.roles.cache.map(r => `${r}`).slice(0).reverse().join(' | ').toString().replace("@everyone | ", "").replace("@everyone", "")
    }
    var userpresence = user.presence.status;
    if (userpresence == "online") userpresence = "<:ONLINE:730989151653986316> Online";
    if (userpresence == "idle") userpresence = "<:IDLE:730984100269391892> Idle";
    if (userpresence == "dnd") userpresence = "<:DND:730935210366992504> Do Not Disturb";
    if (userpresence === "offline") userpresence = "<:OFFLINE:730993056689422357> Offline";
    const embed1 = {
      "color": 0x00ff00,
      "author": {
        name: user.tag,
        icon_url: user.avatarURL(),

      },
      fields: [{
          name: "Joined on:",
          value: moment.utc(guilduser.joinedAt).format('dddd, MMMM Do YYYY'),
        },
        {
          name: "Account Creation Date:",
          value: moment.utc(user.createdAt).format('dddd, MMMM Do YYYY'),
        },
        {
          name: 'User ID:',
          value: user.id,
        },
        {
          name: 'Status:',
          value: userpresence,
        },
        {
          name: "Roles:",
          value: userroles,
        },
        {
          name: "Avatar URL",
          value: user.avatarURL({
            format: "png"
          })
        }
      ]
    }
    message.channel.send({
      embed: embed1
    });
  }
  if(splitMessage[0] == "c" || splitMessage[0] == "compress") {
      splitMessage.shift();
      if(splitMessage.length == 0) return message.channel.send("Not enough arguments");
      let str = splitMessage.join(" ").trim();
      message.channel.send(CompressUrl(str), {code: "txt"});
    }
    if(splitMessage[0] == "u" || splitMessage[0] == "uncompress") {
      splitMessage.shift();
      if(splitMessage.length == 0) return message.channel.send("Not enough arguments");
      let str = splitMessage.join(" ").trim();
      message.channel.send("<" + UncompressUrl(str) + ">");
    }
  if (splitMessage[0] == "twdl") {
    try {

      if(!message.content.includes("http")) {
        message.channel.send("No Video Provided");
        return;
      }
      let videoID = message.content.split(" ");
      for(i in videoID) {
        if (videoID[i].includes("http")) {
          videoID = videoID[i];
        }
      }
        console.log(JSON.stringify(TwitterFetcher.getDetails(TwitterFetcher.parseUrl(videoID).id), null, 2))
        let info = TwitterFetcher.getDetailsConcise(TwitterFetcher.parseUrl(videoID).id);
      
      let video_url = info.videos.variants.sort((a,b)=>{ if(!b.bitrate) return -1; return Number(a.url.split("/")[7].split("x")[0]) > Number(b.url.split("/")[7].split("x")[0]) ? -1 : 1; })[0].url
      const ytembed = {
        "color": 0x00ff00,
        fields: [{
          name: info.user_name,
          value: "**[" + info.title + "](" + video_url + ")**",
        }, ],
        "image": {
          "url": info.thumbnail,
        },
      }
      
      message.channel.send({
        embed: ytembed
      })
    } catch (e) {
      message.channel.send("Something went wrong :/");
      if(message.content.includes("-showerror")) {
        message.channel.send("", {embed:{color:0x00ff00, description: `\`\`\`php\n${e.stack}\n\`\`\``}})
      }
    }
  }
  if (splitMessage[0] == "ytdl") {
    try {

      if(!message.content.includes("http")) {
        message.channel.send("No Video Provided");
        return;
      }
      let videoID = message.content.split(" ");
      for(i in videoID) {
        if (videoID[i].includes("http")) {
          videoID = videoID[i];
        }
      }
      let info = await ytdl.getInfo(videoID);
      let manifest = ytdl.chooseFormat(info.formats, {
        quality: 'highestvideo',
        filter: format => format.container === 'mp4' && format.hasVideo === true && format.hasAudio === true
      })
      const ytembed = {
        "color": 0x00ff00,
        fields: [{
          name: info.videoDetails.ownerChannelName,
          value: "**[" + info.videoDetails.title + "](" + manifest.url + ")**",
        }, ],
        "image": {
          "url": info.videoDetails.thumbnails[info.videoDetails.thumbnails.length - 1].url.split("?")[0],
        },
      }
      message.channel.send({
        embed: ytembed
      })
    } catch (e) {
      message.channel.send("Something went wrong :/");
      if(message.content.includes("-showerror")) {
        message.channel.send("", {embed:{color:0x00ff00, description: `\`\`\`php\n${e.stack}\n\`\`\``}})
      }
    }
  }
  if (splitMessage[0] == "ytinfo") {
    const vid = ytdl(splitMessage[1], {
      filter: format => format.container === 'mp4'
    })
    const info = await ytdl.getInfo(splitMessage[1]);
    var result = JSON.stringify(info, null, 4);
    if (result.length > 2000) {
      fs.writeFile('./temp/FETCH.json', result, function(err) {
        if (err) message.channel.send("An error occured");
      })
      var msg = "Message is over 2000 characters!";
      message.channel.send(msg, {
        files: ["./temp/FETCH.json"]
      }).then(x => {
        fs.writeFile('./temp/FETCH.json', " ", function(err) {
          if (err) return;
        })
      })
    } else {
      message.author.send("```json\n" + JSON.stringify(res, null, 4) + "\n```");
    }
  }
  if (message.content === "kb!servers") {
    message.channel.send("Servers in:\n\n" + client.guilds.cache.map(g => g.name).join("\n"));
  }
  if (splitMessage[0] === "egypt") {
    if (splitMessage[1] == "help") {
      message.channel.send("egypt `emote` `length`");
    } else {
      if (splitMessage[2] == undefined) {
        splitMessage[2] = " ";
      }
      if (splitMessage[2] == "@everyone" || splitMessage[2] == "@here") {
        splitMessage[2] = message.author.toString();
      }
      var strlength = splitMessage[2].split("");
      var length = splitMessage[1];
      if (isNaN(length) || length < 2) {
        length = 3;
      }
      var downnum = "";
      var upnum = "";
      var testnum1 = "";
      var testnum2 = "";
      for (i = 0; i < length; i++) {
        testnum1 = testnum1 + splitMessage[2];
        upnum = upnum + testnum1;
      }
      for (i = 0; i < length - 1; i++) {
        testnum2 = testnum2 + splitMessage[2];
        downnum = testnum2 + downnum;
      }
      var getlength = (upnum + downnum).split("");
      if (getlength.length > 2000) {
        message.channel.send("Too many characters: " + getlength.length + " characters is over 2000 characters");
      } else {
        try {
          var str = "";
          var upstr = "";
          var downstr = "";
          var finalstr = "";
          var test = splitMessage[2];
          for (i = 0; i < length; i++) {
            str = str + test;
            upstr = upstr + str + "\n";
          }
          for (i = 0; i < length - 1; i++) {
            finalstr = finalstr + test;
            downstr = finalstr + "\n" + downstr;
          }
          message.channel.send(upstr + downstr);
        } catch (e) {
          message.channel.send("Something went wrong : /\`\`\`cmd\n" + e.stack + "\`\`\`");
        }
      }
    }
  }
  if (message.content === "kb!widepeepo") {
    // const canvas = Canvas.createCanvas(1200, 200);
    // const ctx = canvas.getContext("2d");
    // var img1 = await Canvas.loadImage('https://cdn.discordapp.com/emojis/691701513155772457.png?v=1');
    // ctx.drawImage(img1, 0, 0, 1200, 200);
    // const attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'testimage.png');
    message.channel.send("Canvas Commands Are Down Temporarily");
  }
  if (message.content === "kb!megaslots") {
    var testingstr = "" + emojis[0];
    if (testingstr == "undefined") {
      message.channel.send("No emotes available");
      return;
    }
    const emojiList = message.guild.emojis.cache.map((e, x) => (x));
    var e1 = emojiList[Math.floor(Math.random() * emojiList.length)];
    var e1id = 'https://cdn.discordapp.com/emojis/' + e1 + '.png';
    var e2 = emojiList[Math.floor(Math.random() * emojiList.length)];
    var e2id = 'https://cdn.discordapp.com/emojis/' + e2 + '.png';
    var e3 = emojiList[Math.floor(Math.random() * emojiList.length)];
    var e3id = 'https://cdn.discordapp.com/emojis/' + e3 + '.png';
    // try {
    //   const canvas = Canvas.createCanvas(1200, 450);
    //   const ctx = canvas.getContext("2d");
    //   var img1 = await Canvas.loadImage(e1id);
    //   var img1h;
    //   var img1w;
    //   var img2h;
    //   var img2w;
    //   var img3h;
    //   var img3w;
    //   if (img1.height >= img1.width) {
    //     img1w = (400 / img1.height) * img1.width;
    //     img1h = 400;
    //   }
    //   if (img1.height < img1.width) {
    //     img1h = (400 / img1.width) * img1.height;
    //     img1w = 400;
    //   }
    //   var img2 = await Canvas.loadImage(e2id);
    //   if (img2.height >= img2.width) {
    //     img2w = (400 / img2.height) * img2.width;
    //     img2h = 400;
    //   }
    //   if (img2.height < img2.width) {
    //     img2h = (400 / img2.width) * img2.height;
    //     img2w = 400;
    //   }
    //   var img3 = await Canvas.loadImage(e3id);
    //   if (img3.height >= img3.width) {
    //     img3w = (400 / img3.height) * img3.width;
    //     img3h = 400;
    //   }
    //   if (img3.height < img3.width) {
    //     img3h = (400 / img3.width) * img3.height;
    //     img3w = 400;
    //   }
    //   ctx.drawImage(img1, ((400 - img1w) / 2), ((400 - img1h) / 2), img1w, img1h);
    //   ctx.drawImage(img2, ((400 - img2w) / 2) + 400, ((400 - img2h) / 2), img2w, img2h);
    //   ctx.drawImage(img3, ((400 - img3w) / 2) + 800, ((400 - img3h) / 2), img3w, img3h);
    //   ctx.font = "bolder 50px HyliaSerifBeta";
    //   ctx.fillStyle = "White";
    //   ctx.fillText("PLEASE PLAY AGAIN", 0, 450);
    //   const attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'testimage.png');
    //   message.channel.send(attachment);
    // } catch (err) {
    //   message.channel.send("Something went wrong :(");
    //   message.channel.send(err.stack);
    // }
    message.channel.send("Canvas Commands Are Down Temporarily");
  }
  if(message.content == "kb!logtest") {
    message.reply("check log")
    console.log("yes?")
  }
  if (splitMessage[0] === "botwtext" || splitMessage[0] === "botw") {
  //   var textstr = "";
  //   if (textstr + message.content.split(/ (.+)/)[1] == "undefined") {
  //     textstr == " ";
  //   } else {
  //     textstr = textstr + message.content.split(/ (.+)/)[1];
  //   }
  //   var lcal;
  //   var cHeight = 70;
  //   lcal = textstr.length;
  //   var splitStr;
  //   splitStr = textstr.match(/.{1,32}/g);
  //   var textlength = textstr.length;
  //   var width = textlength * 20;
  //   const canvas = Canvas.createCanvas(1200, cHeight * splitStr.length);
  //   const ctx = canvas.getContext("2d");
  //   ctx.font = "50px HyliaSerifBeta";
  //   ctx.fillStyle = "white";
  //   ctx.lineWidth = 2;
  //   ctx.strokeStyle = "#1a7ce2";
  //   ctx.strokeText(splitStr.join("\n"), 20, 55);
  //   ctx.fillText(splitStr.join("\n"), 20, 55);
  //   const attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'testimage.png');
  //   message.channel.send(attachment);
  // }
  // if (splitMessage[0] === "sheikahtext" || splitMessage[0] === "sheikah") {
  //   var textstr = "";
  //   if (textstr + message.content.split(/ (.+)/)[1] == "undefined") {
  //     textstr == " ";
  //   } else {
  //     textstr = textstr + message.content.split(/ (.+)/)[1];
  //   }
  //   var textlength = textstr.length;
  //   var splitStr = textstr.match(/.{1,32}/g);
  //   var width = textlength * 20;
  //   const canvas = Canvas.createCanvas(1200, (70 * splitStr.length));
  //   const ctx = canvas.getContext("2d");
  //   ctx.font = "50px Sheikah";
  //   ctx.fillStyle = "white";
  //   ctx.lineWidth = 2;
  //   ctx.strokeStyle = "#1a7ce2";
  //   ctx.strokeText(splitStr.join("\n"), 20, 55);
  //   ctx.fillText(splitStr.join("\n"), 20, 55);
  //   const attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'testimage.png');
  //   message.channel.send(attachment);
  message.channel.send("Canvas Commands Are Down Temporarily");
  }
  if (message.content.includes("<@!702572373261680796>")) {
    message.channel.send("Pinged :0");
  }
  if (message.content === 'kb!hi' || message.content === 'kb!hello') {
    message.reply('Hello!');
  }
  if (message.content === 'kb!good bye' || message.content === 'kb!goodbye' || message.content === "kb!bye") {
    message.channel.send("Bye :wave:");
  }
  if (message.content === 'kb!hype' || message.content === 'kb!yay') {
    message.channel.send('<:POGGERS:726933522383896638> '.repeat(16));
  }
  if (message.content === "kb!cheers") {
    message.channel.send(":beers:");
  }
  if (message.content === "kb!sd" || message.content === "kb!selfdestruct") {
    message.channel.send("Initiating Self Destruct");
    setTimeout(() => {
      message.channel.send("3");
    }, 1000);
    setTimeout(() => {
      message.channel.send("2");
    }, 2000);
    setTimeout(() => {
      message.channel.send("1");
    }, 3000);
    setTimeout(() => {
      message.channel.send("```php\nat users\\Komali\\data\\KomaliBot\\source.zip\\commands\\selfdestruct\\raw\.js \n \[ERROR\] CODE_ID 1A8358HK5 	\n        at line 323532:132 \n        function self_destruction not found \n        unreferenced character \"$\" in script at Line 284619:1\n        invalid variable \"sequence\" at Line 3:142\n        function aborted \n \[\/ERROR\]```");
    }, 4700);
  }
  if (message.content === "kb!pscs") {
    message.channel.send("<a:PSCS:746023931713945652>");
    message.delete();
  }
  if (message.content === "kb!ptest") {
    // :I
    message.channel.send("<a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652>");
    message.channel.send("<a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810>");
    message.channel.send("<a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652>");
    message.channel.send("<a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810><a:PSCS:746023931713945652><a:SCSP:746023920469147810>");
  }
  if (message.content.startsWith("kb!pscs")) {
    var pstr = message.content.split(/ (.+)/)[1];
    var psstr = "";
    if (isNaN(pstr) || pstr < 1) {
      pstr = 1;
    }
    if (pstr > 74) {
      pstr = 74;
    }
    for (i = 0; i < pstr; i++) {
      psstr = psstr + "<a:PSCS:746023931713945652>";
    }
    message.channel.send(psstr);
    message.delete();
  }
  if (message.content.startsWith("kb!ps")) {
    var pstr = message.content.split(/ (.+)/)[1];
    var psstr = "";
    if (isNaN(pstr) || pstr < 1) {
      pstr = 1;
    }
    if (pstr > 75) {
      pstr = 75;
    }
    for (i = 0; i < pstr; i++) {
      psstr = psstr + "<a:ps:746032942031306803>";
    }
    message.channel.send(psstr);
    message.delete();
  }
  if (splitMessage[0] === 'slots' && message.channel.type != "dm") {
    var testingstr = "" + emojis[0];
    if (testingstr == "undefined") {
      message.channel.send("No emotes available");
      return;
    }
    var i;
    var slotStr = "";
    var slotRepeat = splitMessage[1];
    if (isNaN(slotRepeat) || slotRepeat < 2) {
      slotRepeat = 3;
    }
    if (slotRepeat > 50) {
      slotRepeat = 50;
    }
    for (i = 0; i < slotRepeat; i++) {
      slotStr = slotStr + emojis[Math.floor(Math.random() * emojis.length)];
    }
    message.channel.send(slotStr);
    message.channel.send("Please Play Again!");
  }
  if (splitMessage[0] === 'ultraslots' && message.channel.type != "dm") {
    const allemojis = client.emojis.cache.map(e => e.toString());
    const eName = client.emojis.cache.map(x => x.name);
    var i;
    var slotStr = "";
    var slotRepeat = splitMessage[1];
    if (isNaN(slotRepeat) || slotRepeat < 2) {
      slotRepeat = 3;
    }
    if (slotRepeat > 50) {
      slotRepeat = 50;
    }
    for (i = 0; i < slotRepeat; i++) {
      slotStr = slotStr + allemojis[Math.floor(Math.random() * allemojis.length)];
    }
    message.channel.send(slotStr);
    message.channel.send("Please Play Again!");
  }
  if (message.content.startsWith("kb!codeblock")) {
    let _stdout = (s, b = true) => {
      let emb = new Discord.MessageEmbed()
            .setAuthor("stdout/stderr")
            .setColor("#00ff00")
            .setDescription("```php\n" + s + "\n```")
          if(b) message.channel.send(emb);
          return emb;
    }
    var langs = ["```py"]; //ran separately
    for (i = 0; i < langs.length; i++) {
      if (message.content.includes(langs[i])) return;
    }
    let lang = message.content.split("```")[1].split("\n")[0];
    if (!cmdUsers.includes(message.author.id) && (message.content.includes("```js") || message.content.includes("```bf"))) {
      let emb = JSON.parse("{\"color\": 65280, \"author\": {\"name\":\"stdout/stderr\"},  \"description\": \"\`\`\`js\\nError 401: Unauthorized\\n```\" }");
      message.channel.send({
        embed: emb
      });
      return;
    }
    if (cmdUsers.includes(message.author.id)) {
      try {
        for (i = 0; i < langs.length; i++) {
          if (message.content.includes(langs[i])) return;
        }
        var cmd = message.content.split("\n");
        cmd.shift()
        if (cmd[0].includes('```')) {
          cmd.shift();
        }
        if (cmd[cmd.length - 1] == "```") {
          cmd.pop();
        } else if (cmd[cmd.length - 1].includes("```")) {
          cmd[cmd.length - 1] = cmd[cmd.length - 1].replace("\`\`\`", "");
        }
        if (lang == "cpp" || lang == "c++") {
          message.channel.send("Compiling<a:spinny:822587419449622539>").then(m=>{
            let _cpp = cpp(cmd.join("\n"));
            m.edit("", {embed:_stdout(_cpp, false)});
          });
        }
        else if(lang == "bash") {
          try {
            let _result = runBash(cmd.join("\n")).text;
            _stdout(_result);
          }
          catch (e) {
            _stdout(e.stack);
          }
        } 
        else if(lang == "bf" || lang == "brainfuck") {
          if (cmd.toString() == "help") {
            message.channel.send("enter bf code in the format code!input, e.g. ,>,>,<<.>.>.!Hey");
            return;
          }
          try {
            let p = new BrainFParser(cmd.toString());
            let r = p.parse();
            
            if(r.replace(/\n/g, "").replace(/ /g, "") != ""){
              _stdout(r);
            }
          }
          catch(e){
            _stdout(e.stack);
          }
          return
        }
        else if (lang == "js") {
        try {
          let codeblock = (code, callback) => {
            const waitFn = (ev) => {
              return new Promise((resolve, reject) => {
                process.stdout.write = function(d) {
                  if(d) fs.appendFileSync("./log.txt", d.toString());
                }
                process.stderr.write = function(d) {
                  if(d) fs.appendFileSync("./log.txt", d.toString());
                }
                resolve(eval(ev));
              })
            }
            fs.writeFileSync("./log.txt", "");
            let currentstdout = fs.readFileSync("./log.txt").toString();
            var a = waitFn(code)
              .then((a) => {
                
                process.stdout.write = TEMPSTDOUT;
                process.stderr.write = TEMPSTDERR;
                let stdout = fs.readFileSync("./log.txt").toString().substr(0,2000).replace(currentstdout, "");
                callback(stdout.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ""));
              // })
              // .catch(e => {

                 })
              .catch(e=>{
                process.stdout.write = TEMPSTDOUT;
                process.stderr.write = TEMPSTDERR;
                let stdout = fs.readFileSync("./log.txt").toString().substr(0,2000).replace(currentstdout, "");
                callback(e.stack)
              
                message.channel.send("err")
              })

          }
          codeblock(cmd.join("\n"), (stdout) => {
            if (stdout.length > 0) {
              if(typeof stdout == "array") stdout = stdout.join("\n");
              _stdout(stdout);
            }
          })
        } catch (e) {
          _stdout(e.stack);

        }
        }
      else {
        if (rc.search(lang)) {
          let langObj = rc.search(lang);
          rc.run(langObj, cmd.join("\n"), message, _stdout);
        }
      }
      } catch (e) {
        _stdout("Error with program\n\n" + e.stack);
      }
    } else {
      message.channel.send("Missing Permissions");
    }
  }
  if (splitMessage[0] === "minislots") {
    var testingstr = "" + emojis[0];
    if (testingstr == "undefined") {
      message.channel.send("No emotes available");
      return;
    }
    var i;
    var mslotStr = "";
    for (i = 0; i < 3; i++) {
      var randEmote = emojis[Math.floor(Math.random() * emojis.length)];
      mslotStr = mslotStr + randEmote + " ";
    };
    const pogembed = {
      "title": mslotStr,
      "color": 0x00cc00,
      "footer": {
        "text": "Please Play Again!",
      }
    }
    message.channel.send({
      embed: pogembed
    });
  }
  if (splitMessage[0] === "chat") {
    var chatusers = cmdUsers;
    if (chatusers.includes(message.author.id)) {
      message.channel.send(message.content.replace("kb!chat ", ""));
      message.delete();
    } else {
      message.channel.send("Insufficient Permissions!");
    }
  }
  if (splitMessage[0] === "emote") {
    if (splitMessage[3] !== "a") {
      splitMessage[3] = "";
    }
    if (splitMessage[1] === "help") {
      message.channel.send("emote `emote name` `emote id` `a (only if it is animated)`");
      message.channel.send("to get the id, do `\\:emote`, then copy and paste that");
    }
    if (splitMessage[1] != "help") {
      message.channel.send("<" + splitMessage[3] + ":" + splitMessage[1] + ":" + splitMessage[2] + ">");
    }
  }
  if (splitMessage[0] === "randomize") {
    function shuffle(array) { //shamelessly stolen from stackoverflow
      var currentIndex = array.length,
        temporaryValue, randomIndex;
      while (0 !== currentIndex) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
      }
      return array;
    }
    var arr = message.content.split(/ (.+)/)[1].split("");
    shuffle(arr);
    message.channel.send(arr.join(""));
  }
  if (splitMessage[0] == "clipdl") {
    var url = message.content.split(/ (.+)/)[1];
    if (url.includes("?")) {
      url = url.split("?")[0];
    }
    var clipId = url.includes("/") ? url.split("/")[url.split("/").length - 1] : function() {
      return message.channel.send("Invalid URL");
    }();
    fetch(`https://api.twitch.tv/kraken/clips/${clipId}`, {
      method: "GET",
      headers: {
        'Accept': "application/vnd.twitchtv.v5 + json",
        'Client-ID': process.env.clientId
      }
    }).then(x => x.json()).then(json => {
      if (json.error) {
        message.channel.send(`Error ${json.status}: ${json.error}\nMessage: ${json.message}`);
        return;
      }
      try {
        if (!json.thumbnails) {
          message.channel.send("Error while finding ID");
          return;
        }
        let rawId = json.thumbnails[Object.keys(json.thumbnails)[0]].split("AT-cm%")[1].split("-")[0];
        message.channel.send(`Success: https://production.assets.clips.twitchcdn.net/AT-cm%${rawId}.mp4`)
      } catch (err) {
        message.channel.send("Error: \`\`\`cmd\n" + err.stack + "\n\`\`\`");
      }
    })
  }
  if (splitMessage[0] == "src") {
    try {
      message.channel.send("Please wait, fetching data...").then(msg => {
        getsrc.getsrcinfo(splitMessage[1], function(err, username, rankemote, flag, imgurl, weblink, usercountry,
          acccreation, modfor, pbs, runs, links) {
          if (err) {
            msg.edit(err);
            return;
          } else {
            const embed = {
              color: 0x00ff00,
              title: rankemote + flag + username,
              author: {
                name: username,
                icon_url: imgurl,
              },
              fields: [{
                  name: "Weblink",
                  value: weblink,
                },
                {
                  name: "Location",
                  value: usercountry
                },
                {
                  name: "Account Creation Date",
                  value: acccreation,
                },
                {
                  name: "Moderator for",
                  value: modfor,
                },
                {
                  name: "\# of Personal Bests",
                  value: pbs,
                },
                {
                  name: "\# of Total Runs Submitted",
                  value: runs
                },
                {
                  name: "Links:",
                  value: links.join('\n')
                },
              ],
            }
            msg.edit(" ", {
              embed: embed
            })
          }
        });
      })
    } catch (e) {
      message.channel.send(e);
    }
  }
  if (splitMessage[0] == "stack") {
    require("./codes/stack.js")(message, Discord, client, splitMessage);
  }
  if (splitMessage[0] == "twitchapi") {
    var game = message.content.split(/ (.+)/)[1];
    game = game.split(/ (.+)/)[1];
    game = game.split("\\")[0];
    var url = "";
    var streamType = "";
    if (splitMessage[1] == "users" || splitMessage[1] == "user") {
      streamType = "users";
      url = "https://api.twitch.tv/helix/users?login=";
    } else if (splitMessage[1] == "get" || splitMessage[1] == "GET") {
      streamType = "GET";
      url = "";
    } else if (splitMessage[1] == "query") {
      streamType = "query";
      url = "https://api.twitch.tv/helix/search/categories?query=";
    } else if (splitMessage[1] == "stream" || splitMessage[1] == "streams") {
      streamType = "stream";
      url = "https://api.twitch.tv/helix/streams/?user_login=";
    } else if (splitMessage[1] == "game" || splitMessage[1] == "games") {
      if (!isNaN(splitMessage[2])) {
        streamType = "game";
        url = "https://api.twitch.tv/helix/games?id=";
      } else {
        streamType = "game";
        url = "https://api.twitch.tv/helix/games?name=";
      }
    } else {
      message.channel.send("Please specify a valid scope. Available scopes are: stream, game, user, get, query");
      return;
    }
    var outCmd = message.content.split(" \\ ")[1];
    fetch('https://id.twitch.tv/oauth2/token?client_id=' + process.env.clientId + "&client_secret=" + process.env.clientSecret +
        "&grant_type=client_credentials", {
          method: 'POST',
        })
      .then(res => res.json())
      .then(res => {
        console.log(res)
        var token = res.access_token;
        try {
          fetch(url + game, {
              method: 'GET',
              headers: {
                'Accept': "application/vnd.twitchtv.v5 + json",
                'Client-ID': process.env.clientId,
                'Authorization': 'Bearer ' + token,
              }
            })
            .then(res => res.json())
            .then(res => {
              var result = JSON.stringify(res, null, 4);
              if (result.length > 2000 && (outCmd == "json" || !outCmd)) {
                fs.writeFile('./temp/FETCH.json', result, function(err) {
                  if (err) message.channel.send("An error occured");
                })
                var msg = "Message is over 2000 characters!";
                if (outCmd == "json") {
                  msg = "";
                }
                message.channel.send(msg, {
                  files: ["./temp/FETCH.json"]
                }).then(x => {
                  fs.writeFile('./temp/FETCH.json', " ", function(err) {
                    if (err) return;
                  })
                })
              } else {
                if (outCmd == "dm") {
                  if (result.length > 2000) {
                    message.author.send(result, {
                      split: true,
                      code: "yml"
                    })
                  } else {
                    message.author.send("```json\n" + JSON.stringify(res, null, 4) + "\n```")
                  }
                }
                message.channel.send("```json\n" + JSON.stringify(res, null, 4) + "\n```")
              }
            })
        } catch (e) {
          console.log(e);
        }
      })
  }
});
client.login(process.env.TOKEN);
// process.on("exit",function() {
//         childprocess.spawn(process.argv.shift(),process.argv,{
//             "cwd":process.cwd(),
//             "detached":true,
//             "stdio":"inherit"
//         });
// });