/*
MagicalSurges
Version 0.0.4
Github <a href="https://github.com/nmrcarroll/roll20-api-scripts/tree/master/MagicalSurges" rel="nofollow">https://github.com/nmrcarroll/roll20-api-scripts/tree/master/MagicalSurges</a>
*/
var MagicalSurges = MagicalSurges || (function () {
  let version = '0.0.5',
    surgeTable,
    arrayTable,
    checkInstall = function () {
      // initalize the state to store our sorcerers in if not already done.
      if (!state.MagicalSurges) {
        state.MagicalSurges = {
          sorc: [],
        };
      }
      // Attempt to locate the rollable table
      surgeTable = findObjs({
        type: 'rollabletable',
        name: 'MagicalSurges',
      })[0];
      // If rollable table does not exist, make one.
      if (!surgeTable) {
        surgeTable = createObj('rollabletable', {
          name: 'MagicalSurges',
        });
        // Create a dummy item in the rollable table.
        createObj('tableitem', {
          name: "DELETE ME WHEN YOU'VE ADDED YOUR OWN SURGES",
          rollabletableid: surgeTable.id,
        });
      }
      // store all the items in the rollable table for later use.
      arrayTable = findObjs({
        type: 'tableitem',
        rollabletableid: surgeTable.id,
      });
    },
    // called when changes are made to the rollable table, reloads the list we have stored.
    loadTable = function (obj) {
      if (obj.get('_rollabletableid') == surgeTable.id) {
        arrayTable = findObjs({
          type: 'tableitem',
          rollabletableid: surgeTable.id,
        });
      }
    },
    // adds player id to the state
    addPlayer = function (ids) {
      state.MagicalSurges.sorc = [...new Set([...state.MagicalSurges.sorc, ...ids])];
    },
    // remove player id from the state
    removePlayer = function (ids) {
      state.MagicalSurges.sorc = state.MagicalSurges.sorc.filter(id => !ids.includes(id));
    },
    idNameConvert = function (charNames, args) {
      // Remove all spaces from string.
      const keyFormat = n => (n || '').toLowerCase().replace(/\s+/g, '');
      const allCharIds = [];
      const charId2Name = {};
      // Creates a dictionary of all characters and their ID's
      const charKey2Id = findObjs({
        type: 'character',
      }).reduce((m, c) => {
        const name = c.get('name');
        m[keyFormat(name)] = c.id;
        allCharIds.push(c.id);
        charId2Name[c.id] = name;
        return m;
      }, {});
      // find id matching character name entered or id entered
      const ids = charNames.reduce((m, n) => {
        const kn = keyFormat(n);
        if (charKey2Id.hasOwnProperty(kn)) {
          m.push(charKey2Id[kn]);
        }
        return m;
      }, args.slice(2).filter(id => allCharIds.includes(id)));
      return [ids, charId2Name];
    },
    // Checks if the message is a spell from one of our monitored characters
    checkSpell = function (msg) {
      const character_id = (findObjs({
        type: 'character',
        name: (msg.content.match(/charname=([^\n{}]*[^"\n{}])/) || [])[1],
      })[0] || {
        id: 'API',
      }).id;
      if (state.MagicalSurges.sorc.includes(character_id)) {
        let spell_level = msg.content.match(/spelllevel=([^\n{}]*[^"\n{}])/);
        // Make sure we're not pulling from the first regex
        if (spell_level != null) {
          spell_level = RegExp.$1;
        }
        const cantrip = msg.content.includes('cantrip}}');
        const whisper = msg.target;
        // If a spell was rolled, automatically roll a d20 to see if a surge happens
        if (!cantrip && (spell_level > 0 || msg.rolltemplate == 'spell')) {
          const roll = randomInteger(20);
          if (!cantrip && (spell_level > 0 || msg.rolltemplate == 'spell')) {
            let chatMesg = '';
            chatMesg = `&{template:simple} {{rname=Wild}} {{r1=${roll}}} {{normal=1}}`;
            if (whisper == undefined) {
              sendChat(msg.who, chatMesg);
            } else {
              sendChat(msg.who, `/w gm ${chatMesg}`);
              sendChat(msg.who, `/w ${msg.who} ${chatMesg}`);
            }
          }
        }
      }
    },
    makeSurge = function () {
      const roll = randomInteger(arrayTable.length);
      const effect = arrayTable[roll - 1].get('name');
      let chatMesg = '';
      chatMesg = `&{template:atk} {{rname=WildRoll}} {{rnamec=rnamec}} {{r1=${roll}}} {{normal=1}} {{desc=${effect}}}`;
      return chatMesg;
    },
    handleInput = function (msg) {
      const spellRollTemplates = ['spell', 'atk', 'dmg', 'atkdmg'];
      if (msg.type !== 'api') {
        if (msg && msg.rolltemplate && spellRollTemplates.includes(msg.rolltemplate)) {
          const roll = checkSpell(msg);
          const whisper = msg.target;
          if (roll == 1) {
            const mSurge = makeSurge();
            if (whisper == undefined) {
              sendChat(msg.who, mSurge);
            } else {
              sendChat(msg.who, `/w gm ${mSurge}`);
              sendChat(msg.who, `/w ${msg.who} ${mSurge}`);
            }
            return roll;
          }
        }
      }
      const charNames = msg.content.split(/\s+--/);
      const args = msg.content.split(/\s+/);
      // Check for specific script commands and respond
      switch (args[0]) {
        case '!MagicalSurge':
          if (args.length === 1) {
            sendChat('MagicalSurge', `/direct ${makeSurge()}`);
            break;
          }
          switch (args[1]) {
            case 'gm':
              sendChat('MagicalSurge', `/w gm ${makeSurge()}`);
              break;
            case 'add':
            case 'remove':
              if (playerIsGM(msg.playerid) && (args.length > 2 || charNames.length)) {
                const idReturn = idNameConvert(charNames, args);
                const ids = idReturn[0];
                const charId2Name = idReturn[1];
                if (ids.length) {
                  if (args[1] === 'add') {
                    sendChat('MagicalSurge', `/w gm Adding Characters: ${ids.map(id => charId2Name[id]).join(', ')}`);
                    addPlayer(ids);
                    sendChat('MagicalSurge', `/w gm Current Sorcerers: ${state.MagicalSurges.sorc.map(id => charId2Name[id]).join(', ')}`);
                  } else {
                    sendChat('MagicalSurge', `/w gm Removing Characters: ${ids.map(id => charId2Name[id]).join(', ')}`);
                    removePlayer(ids);
                    sendChat('MagicalSurge', `/w gm Current Sorcerers: ${state.MagicalSurges.sorc.map(id => charId2Name[id]).join(', ')}`);
                  }
                } else {
                  sendChat('MagicalSurge', '/w gm No valid characters found.  Please be sure to use the character_id or character name.');
                }
              }
          }
      }
    },
    registerEventHandlers = function () {
      on('chat:message', handleInput);
      on('add:tableitem', loadTable);
      on('change:tableitem', loadTable);
      on('destroy:tableitem', loadTable);
    };
  return {
    CheckInstall: checkInstall,
    RegisterEventHandlers: registerEventHandlers,
  };
}());
on('ready', () => {
  MagicalSurges.CheckInstall();
  MagicalSurges.RegisterEventHandlers();
});