/* -------------------------------------------- */

import { ChatUtility } from "./chat-utility.js";
import { DeDraconique } from "./de-draconique.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js";

const rddRollNumeric = /(\d+)\s*([\+\-]?\d+)?\s*(s)?/;

/* -------------------------------------------- */
export class RdDCommands {

  static init() {
    if (!game.system.rdd.commands) {
      const rddCommands = new RdDCommands();
      rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
      rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
      rddCommands.registerCommand({ path: ["/table", "queues"], func: (content, msg, params) => RdDRollTables.getQueue(), descr: "Tire une Queue de Dragon" });
      rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre(), descr: "Tire une Ombre de Dragon" });
      rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR(), descr: "Tire une Tête de Dragon pour Hauts Revants" });
      rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete(), descr: "Tire une Tête de Dragon" });
      rddCommands.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle(), descr: " Tire un Souffle de Dragon" });
      rddCommands.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot(), descr: "Tire une carte du Tarot Draconique" });
      rddCommands.registerCommand({ path: ["/table", "tmr"], func: (content, msg, params) => TMRUtility.getTMRAleatoire(), descr: "Tire une case aléatoire des Terres médianes" });

      rddCommands.registerCommand({ path: ["/tmra"], func: (content, msg, params) => TMRUtility.getTMRAleatoire(), descr: "Tire une case aléatoire des Terres médianes" });
      rddCommands.registerCommand({
        path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params),
        descr: "Syntaxe: <strong>/tmrr case jet</strong><br>Détermine quelle est la rencontre dans la case pour le jet<br>Exemple: <strong>/tmrr forêt 50</strong>"
      });

      rddCommands.registerCommand({
        path: ["/rdd"], func: (content, msg, params) => rddCommands.rollRdd(msg, params),
        descr: `Effectue un jet de dés dans la table de résolution. Exemples:
      <br><strong>/rdd</strong> ouvre la table de résolution
      <br><strong>/rdd 10 3</strong> effectue un jet 10 à +3
      <br><strong>/rdd 10 +2</strong> effectue un jet 10 à +2
      <br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2
      <br><strong>/rdd 15 0 s</strong> effectue un jet 15 à 0, avec significative requise
      `
      });
      rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });

      rddCommands.registerCommand({
        path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]),
        descr: `Permet de payer un montant. Exemples:
      <br><strong>/payer 5s 10d</strong> permet d'envoyer un message pour payer 5 sols et 10 deniers
      <br><strong>/payer 10d</strong> permet d'envoyer un message pour payer 10 deniers
      `
      });
      game.system.rdd.commands = rddCommands;
    }
  }
  constructor() {
    this.commandsTable = {};
  }

  registerCommand(command) {
    this._addCommand(this.commandsTable, command.path, '', command);
  }

  _addCommand(targetTable, path, fullPath, command) {
    if (!this._validateCommand(targetTable, path, command)) {
      return;
    }
    const term = path[0];
    fullPath = fullPath+term+' '
    if (path.length == 1) {
      command.descr = `<strong>${fullPath}</strong>: ${command.descr}`;
      targetTable[term] = command;
    }
    else {
      if (!targetTable[term]) {
        targetTable[term] = { subTable: {} };
      }
      this._addCommand(targetTable[term].subTable, path.slice(1), fullPath, command)
    }
  }

  _validateCommand(targetTable, path, command) {
    if (path.length > 0 && path[0] && command.descr && (path.length != 1 || targetTable[path[0]] == undefined)) {
      return true;
    }
    console.warn("RdDCommands._validateCommand failed ", targetTable, path, command);
    return false;
  }


  /* -------------------------------------------- */
  /* Manage chat commands */
  processChatCommand(commandLine, content, msg) {
    // Setup new message's visibility
    let rollMode = game.settings.get("core", "rollMode");
    if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
    if (rollMode === "blindroll") msg["blind"] = true;
    msg["type"] = 0;

    let command = commandLine[0];
    let params = commandLine.slice(1);

    return this.process(command, params, content, msg);
  }

  process(command, params, content, msg) {
    return this._processCommand(this.commandsTable, command, params, content, msg);
  }

  _processCommand(commandsTable, name, params, content = '', msg = {}, path = "") {
    let command = commandsTable[name];
    path = path + name + " ";
    if (command && command.subTable) {
      if (params[0]) {
        return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
      }
      else {
        this.help(msg, command.subTable);
        return true;
      }
    }
    if (command && command.func) {
      if (command.func(content, msg, params) === false) {
        this._displayHelp(msg, `${path}: ${command.descr}`);
      }
      return true;
    }
    return false;
  }

  /* -------------------------------------------- */
  help(msg, table = undefined) {
    let list = []
    this._buildSubTableHelp(list, table || this.commandsTable);
    const messageAide = list.reduce((a, b) => a + '</li><li class="list-item">' + b);
    msg.whisper = [game.user._id];
    msg.content = `Commandes disponibles<ul class="alterne-list"><li class="list-item">${messageAide}</li></ul>`;
    ChatMessage.create(msg);
  }

  /* -------------------------------------------- */
  _buildSubTableHelp(list, table) {
    for (let [name, command] of Object.entries(table)) {
      if (command) {
        if (command.subTable) {
          this._buildSubTableHelp(list, command.subTable);
        } else {
          list.push(command.descr);
        }
      }
    }
    return list.sort();
  }


  getRencontreTMR(params) {
    if (params.length == 2) {
      return TMRUtility.getRencontre(params[0], params[1])
    }
    else {
      return false;
    }
  }

  async rollRdd(msg, params) {
    if (params.length == 0) {
      RdDRollResolutionTable.open();
    }
    else {
      let flatParams = params.reduce((a, b) => `${a} ${b}`);
      const numericParams = flatParams.match(rddRollNumeric);
      if (numericParams) {
        const carac = Misc.toInt(numericParams[1]);
        const diff = Misc.toInt(numericParams[2] || 0);
        const significative = numericParams[3] == 's'
        await this.rollRdDNumeric(msg, carac, diff, significative);
        return;
      }
    }
  }

  async rollRdDNumeric(msg, carac, diff, significative = false) {
    let rollData = {
      caracValue: carac,
      finalLevel: diff,
      showDice: true,
      diviseur: significative ? 2 : 1,
      show: { title: "Table de résolution" }
    };
    await RdDResolutionTable.rollData(rollData);
    msg.content = await RdDResolutionTable.buildRollDataHtml(rollData);
    ChatUtility.chatWithRollMode(msg, game.user.name);
  }

  async rollDeDraconique(msg) {
    let rollMode = game.settings.get("core", "rollMode");
    let ddr = new DeDraconique().evaluate();
    await RdDDice.show(ddr, rollMode);
    msg.content = `Lancer d'un Dé draconique: ${ddr.total}`;
    ChatUtility.createChatMessage(msg, rollMode, game.user.name);
  }
}

