/* -------------------------------------------- */
import { Hero6Utility } from "./hero6-utility.js";
import { Hero6RollDialog } from "./hero6-roll-dialog.js";
import { Hero6LiftDice } from "./hero6-lift-dice.js";

/* -------------------------------------------- */
const __speed2Segments = [[0], [7], [6, 12], [4, 8, 12], [3, 6, 9, 12], [3, 5, 8, 10, 12], [2, 4, 6, 8, 10, 12],
[2, 4, 6, 7, 9, 11, 12], [2, 3, 5, 6, 8, 9, 11, 12], [2, 3, 4, 6, 7, 8, 10, 11, 12], [2, 3, 4, 5, 6, 8, 9, 10, 11, 12],
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]]

/* -------------------------------------------- */
/* -------------------------------------------- */
/**
 * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
 * @extends {Actor}
 */
export class Hero6Actor extends Actor {

  /* -------------------------------------------- */
  /**
   * Override the create() function to provide additional SoS functionality.
   *
   * This overrided create() function adds initial items 
   * Namely: Basic skills, money, 
   *
   * @param {Object} data        Barebones actor data which this function adds onto.
   * @param {Object} options     (Unused) Additional options which customize the creation workflow.
   *
   */

  static async create(data, options) {

    // Case of compendium global import
    if (data instanceof Array) {
      return super.create(data, options);
    }
    // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
    if (data.items) {
      let actor = super.create(data, options);
      return actor;
    }

    if (data.type == 'character' || data.type == 'minion') {
      const maneuvers = await Hero6Utility.loadCompendium("fvtt-hero-system-6.maneuvers")
      let maneuversObj = maneuvers.map(i => i.toObject())
      data.items = maneuversObj.filter(m => m.system.isstock)
    }

    return super.create(data, options);
  }

  /* -------------------------------------------- */
  prepareBaseData() {
  }

  /* -------------------------------------------- */
  async prepareData() {
    super.prepareData();
  }

  /* -------------------------------------------- */
  computeDerivatedData() {
    let newSTREND = this.computeSTREND()
    if (newSTREND != this.system.characteristics.str.strend) {
      this.update({ 'system.characteristics.str.strend': newSTREND })
    }
  }
  /* -------------------------------------------- */
  performMigration() {
    // Fix OCV/OMCV rollable
    if (!this.system.characteristics.ocv.hasroll) {
      this.update({ 'system.characteristics.ocv.hasroll': true, 'system.characteristics.omcv.hasroll': true })
    }
  }
  /* -------------------------------------------- */
  computeDicesValue() {
    this.system.biodata.presenceattack = Hero6Utility.getDerivatedDiceFormulas(this.system.characteristics.pre.value)
    this.system.characteristics.str.strdice = Hero6LiftDice.getLiftDice(this.system.characteristics.str.value)
    this.system.characteristics.str.lift = Hero6LiftDice.getLift(this.system.characteristics.str.value)
  }
  /* -------------------------------------------- */
  prepareDerivedData() {

    if (this.type == 'character' || game.user.isGM) {
      this.system.encCapacity = this.getEncumbranceCapacity()
      this.buildContainerTree()
      this.computeDerivatedData()
      this.computeDicesValue()
    }

    super.prepareDerivedData();
  }

  /* -------------------------------------------- */
  _preUpdate(changed, options, user) {

    super._preUpdate(changed, options, user);
  }

  /* -------------------------------------------- */
  getEncumbranceCapacity() {
    let numLift = this.system.characteristics.str.lift.match(/\d*\s/g)
    if (numLift && numLift[0] && Number(numLift[0])) {
      return numLift[0] / 2
    }
  }

  /* -------------------------------------------- */
  getMoneys() {
    let comp = this.items.filter(item => item.type == 'currency');
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp;
  }
  getEquippedWeapons() {
    let comp = duplicate(this.items.filter(item => item.type == 'weapon' && item.system.equipped) || []);
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp;
  }
  /* -------------------------------------------- */
  getArmors() {
    let comp = duplicate(this.items.filter(item => item.type == 'armor') || []);
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp;
  }
  getEquippedArmor() {
    let comp = this.items.find(item => item.type == 'armor' && item.system.equipped)
    if (comp) {
      return duplicate(comp)
    }
    return undefined
  }
  /* -------------------------------------------- */
  getShields() {
    let comp = duplicate(this.items.filter(item => item.type == 'shield') || []);
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp;
  }
  getEquippedShield() {
    let comp = this.items.find(item => item.type == 'shield' && item.system.equipped)
    if (comp) {
      return duplicate(comp)
    }
    return undefined
  }
  /* -------------------------------------------- */
  getRace() {
    let race = this.items.filter(item => item.type == 'race')
    return race[0] ?? [];
  }
  /* -------------------------------------------- */
  checkAndPrepareEquipment(item) {
  }

  /* -------------------------------------------- */
  checkAndPrepareEquipments(listItem) {
    for (let item of listItem) {
      this.checkAndPrepareEquipment(item)
    }
    return listItem
  }

  /* -------------------------------------------- */
  getItemById(id) {
    let item = this.items.find(item => item.id == id);
    if (item) {
      item = duplicate(item)
    }
    return item;
  }

  /* -------------------------------------------- */
  async _preCreate(data, options, user) {
    await super._preCreate(data, options, user);

    // Configure prototype token settings
    const prototypeToken = {};
    if (this.type === "character") Object.assign(prototypeToken, {
      sight: { enabled: true }, actorLink: true, disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
    });
    this.updateSource({ prototypeToken });
  }

  /* -------------------------------------------- */
  prepareSkill(skill) {
    skill.roll = 0
    skill.charac = "N/A"
    skill.system.skilltype = skill.system.skilltype.toLowerCase()
    if (skill.system.skillfamiliarity) {
      skill.roll = 8;
    } else if (skill.system.skillprofiency) {
      skill.roll = 10;
    } else if (skill.system.skilltype == "agility") {
      skill.charac = "dex"
      let charac = duplicate(this.system.characteristics.dex)
      this.prepareCharacValues(charac)
      skill.roll = charac.roll
    } else if (skill.system.skilltype == "interaction") {
      skill.charac = "pre"
      let charac = duplicate(this.system.characteristics.pre)
      this.prepareCharacValues(charac)
      skill.roll = charac.roll
    } else if (skill.system.skilltype == "intellect") {
      skill.charac = "int"
      let charac = duplicate(this.system.characteristics.int)
      this.prepareCharacValues(charac)
      skill.roll = charac.roll
    } else if (skill.system.skilltype == "background") {
      skill.roll = 11
    } else if (skill.system.skilltype == "custom") {
      if (skill.system.characteristic == "manual") {
        skill.roll = skill.system.base
      } else {
        skill.charac = (skill.system.characteristic == "") ? "str" : skill.system.characteristic
        let charac = duplicate(this.system.characteristics[skill.system.characteristic])
        this.prepareCharacValues(charac)
        skill.roll = charac.roll
      }
    }
    console.log("SILL", skill)
    if (skill.system.levels > 0) {
      skill.roll += skill.system.levels
    }
  }

  /* -------------------------------------------- */
  prepareManeuver(maneuver) {

    maneuver.roll = 11 + this.system.characteristics.ocv.value
    if (Number(maneuver.system.ocv)) {
      maneuver.roll += Number(maneuver.system.ocv)
    } else {
      maneuver.noOCV = true
    }
  }

  /* -------------------------------------------- */
  getSkills() {
    let comp = duplicate(this.items.filter(item => item.type == 'skill') || [])
    for (let skill of comp) {
      this.prepareSkill(skill)
    }
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp
  }
  getPerks() {
    let comp = duplicate(this.items.filter(item => item.type == 'perk') || [])
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp
  }
  async getPowers() {
    let comp = duplicate(this.items.filter(item => item.type == 'power') || [])
    for (let c of comp) {
      c.enrichDescription = c.name + "<br>" + await TextEditor.enrichHTML(c.system.description, { async: true })
      c.enrichNotes = c.name + "<br>" + await TextEditor.enrichHTML(c.system.notes, { async: true })
    }
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp
  }
  getTalents() {
    let comp = duplicate(this.items.filter(item => item.type == 'talent') || [])
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp
  }
  getComplications() {
    let comp = duplicate(this.items.filter(item => item.type == 'complication') || [])
    Hero6Utility.sortArrayObjectsByName(comp)
    return comp
  }

  /* -------------------------------------------- */
  async equipItem(itemId) {
    let item = this.items.find(item => item.id == itemId)
    if (item && item.system) {
      if (item.type == "armor") {
        let armor = this.items.find(item => item.id != itemId && item.type == "armor" && item.system.equipped)
        if (armor) {
          ui.notifications.warn("You already have an armor equipped!")
          return
        }
      }
      if (item.type == "shield") {
        let shield = this.items.find(item => item.id != itemId && item.type == "shield" && item.system.equipped)
        if (shield) {
          ui.notifications.warn("You already have a shield equipped!")
          return
        }
      }
      let update = { _id: item.id, "system.equipped": !item.system.equipped };
      await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
    }
  }

  /* -------------------------------------------- */
  compareName(a, b) {
    if (a.name < b.name) {
      return -1;
    }
    if (a.name > b.name) {
      return 1;
    }
    return 0;
  }
  getManeuvers() {
    let maneuvers = {
      general: this.items.filter(item => item.type == "maneuver" && item.system.maneuvertype == "general"),
      offensive: this.items.filter(item => item.type == "maneuver" && item.system.maneuvertype == "offensive"),
      defensive: this.items.filter(item => item.type == "maneuver" && item.system.maneuvertype == "defensive"),
      mental: this.items.filter(item => item.type == "maneuver" && item.system.maneuvertype == "mental")
    }
    Hero6Utility.sortArrayObjectsByName(maneuvers.general)
    Hero6Utility.sortArrayObjectsByName(maneuvers.offensive)
    Hero6Utility.sortArrayObjectsByName(maneuvers.defensive)
    Hero6Utility.sortArrayObjectsByName(maneuvers.mental)
    return maneuvers
  }
  getAllManeuvers() {
    let maneuvers = this.items.filter(item => item.type == "maneuver")
    Hero6Utility.sortArrayObjectsByName(maneuvers)
    return maneuvers
  }
  getNonStockManeuvers() {
    let maneuvers = this.items.filter(item => item.type == "maneuver" && !item.system.isstock)
    Hero6Utility.sortArrayObjectsByName(maneuvers)
    return maneuvers
  }
  getEquipments() {
    let list = this.items.filter(item => item.type == "equipment" && item.system.subtype == "equipment");
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getMoneys() {
    let list = this.items.filter(item => item.type == "equipment" && item.system.subtype == "money");
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getWeapons() {
    let list = this.items.filter(item => item.type == "equipment" && item.system.subtype == "weapon");
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getArmors() {
    let list = this.items.filter(item => item.type == "equipment" && item.system.subtype == "armor");
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getShields() {
    let list = this.items.filter(item => item.type == "equipment" && item.system.subtype == "shield");
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getEquipmentsMoneys() {
    let list = duplicate(this.items.filter(item => item.type == "equipment" && (item.system.subtype == "equipment" || item.system.subtype == "money")) || [])
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }
  getEquipmentsOnly() {
    let list = duplicate(this.items.filter(item => item.type == "equipment" && item.system.subtype == "equipment") || [])
    Hero6Utility.sortArrayObjectsByName(list)
    return list
  }

  /* ------------------------------------------- */
  buildContainerTree() {
    let equipments = duplicate(this.items.filter(item => item.type == "equipment") || []);
    let enc = 0
    let value = 0
    for (let equip1 of equipments) {
      if (Number(equip1.system.weight) && Number(equip1.system.quantity)) {
        enc += equip1.system.weight * equip1.system.quantity
      }
      if (Number(equip1.system.value) && Number(equip1.system.quantity)) {
        value += equip1.system.value * equip1.system.quantity
      }
    }
    // Store local values
    this.encCurrent = enc
    this.totalValue = value
  }

  /* -------------------------------------------- */
  async incDecHP(formula) {
    let dmgRoll = new Roll(formula + "[dark-starsorange]").roll({ async: false })
    await Hero6Utility.showDiceSoNice(dmgRoll, game.settings.get("core", "rollMode"))
    let hp = duplicate(this.system.secondary.hp)
    hp.value = Number(hp.value) + Number(dmgRoll.total)
    this.update({ 'system.secondary.hp': hp })
    return Number(dmgRoll.total)
  }

  /* -------------------------------------------- */
  async addObjectToContainer(itemId, containerId) {
    let container = this.items.find(item => item.id == containerId && item.system.iscontainer)
    let object = this.items.find(item => item.id == itemId)
    if (container) {
      if (object.system.iscontainer) {
        ui.notifications.warn("Only 1 level of container allowed")
        return
      }
      let alreadyInside = this.items.filter(item => item.system.containerid && item.system.containerid == containerId);
      if (alreadyInside.length >= container.system.containercapacity) {
        ui.notifications.warn("Container is already full !")
        return
      } else {
        await this.updateEmbeddedDocuments("Item", [{ _id: object.id, 'system.containerid': containerId }])
      }
    } else if (object?.system?.containerid) { // remove from container
      console.log("Removeing: ", object)
      await this.updateEmbeddedDocuments("Item", [{ _id: object.id, 'system.containerid': "" }]);
    }
  }

  /* -------------------------------------------- */
  async preprocessItem(event, item, onDrop = false) {
    let dropID = $(event.target).parents(".item").attr("data-item-id") // Only relevant if container drop
    let objectID = item.id || item._id
    this.addObjectToContainer(objectID, dropID)
    return true
  }

  /* -------------------------------------------- */
  async equipGear(equipmentId) {
    let item = this.items.find(item => item.id == equipmentId);
    if (item?.system) {
      let update = { _id: item.id, "system.equipped": !item.system.equipped };
      await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
    }
  }
  /* -------------------------------------------- */
  async cleanCombat() {
    await this.setFlag("world", "hold-action", false)
    await this.setFlag("world", "abort-action", { state: false, count: 0 })
  }
  async holdAction() {
    await this.disableAbortAction()
    if (this.getFlag("world", "hold-action")) {
      await this.setFlag("world", "hold-action", false)
      //game.combat.holdAction(this.id, false)
      game.combat.forceHold(this, false)
      return false
    } else {
      await this.setFlag("world", "hold-action", true)
      //game.combat.holdAction(this.id, false)      
      game.combat.forceHold(this, true)
      return true
    }
  }
  async disableHoldAction() {
    await this.setFlag("world", "hold-action", false)
  }
  async disableAbortAction() {
    await this.setFlag("world", "abort-action", { state: false, count: 0 })
  }
  async abortAction() {
    await this.disableHoldAction()
    let abort = this.getFlag("world", "abort-action")
    if (abort.state) {
      await this.setFlag("world", "abort-action", { state: false, count: 0 })
      game.combat.forceAbort(this, false)
      //game.combat.abortAction(this.id, false)
    } else {
      await this.setFlag("world", "abort-action", { state: true, count: 0 })
      game.combat.forceAbort(this, true)
      //game.combat.abortAction(this.id, true)
    }
  }
  async incAbortActionCount() {
    let abort = this.getFlag("world", "abort-action")
    if (abort.state) {
      abort.count++
      await this.setFlag("world", "abort-action", abort)
      if (abort.count == 2) {
        return true
      }
    }
    return false
  }
  getHoldAction() {
    return this.getFlag("world", "hold-action")
  }
  getAbortAction() {
    let abort = this.getFlag("world", "abort-action")
    return abort?.state || false
  }

  /* -------------------------------------------- */
  hasPhase(segmentNumber) {
    let index = Math.min(Math.max(this.system.characteristics.spd.value, 1), 12) // Security bounds
    let phases = __speed2Segments[index]
    console.log("index", segmentNumber, index, phases, phases.includes(segmentNumber), __speed2Segments)
    return phases.includes(segmentNumber)
  }
  /* -------------------------------------------- */
  getSegments() {
    let index = Math.min(Math.max(this.system.characteristics.spd.value, 1), 12) // Security bounds
    //console.log("INDEX", index, __speed2Segments[index])
    return __speed2Segments[index]
  }
  getPhasesString() {
    let index = Math.min(Math.max(this.system.characteristics.spd.value, 1), 12) // Security bounds
    return __speed2Segments[index].toString()
  }
  /* -------------------------------------------- */
  getBaseInit(turn) {
    if (turn != this.turn) {
      let r = new Roll("1d6").roll({ async: false })
      this.currentInit = Number(this.system.characteristics.dex.initiative) + Number(((r.total / 10).toFixed(2)))
      this.turn = turn
    }
    return this.currentInit
  }

  /* -------------------------------------------- */
  getSubActors() {
    let subActors = [];
    for (let id of this.system.subactors) {
      subActors.push(duplicate(game.actors.get(id)))
    }
    return subActors;
  }
  /* -------------------------------------------- */
  async addSubActor(subActorId) {
    let subActors = duplicate(this.system.subactors);
    subActors.push(subActorId);
    await this.update({ 'system.subactors': subActors });
  }
  /* -------------------------------------------- */
  async delSubActor(subActorId) {
    let newArray = [];
    for (let id of this.system.subactors) {
      if (id != subActorId) {
        newArray.push(id);
      }
    }
    await this.update({ 'system.subactors': newArray });
  }

  /* -------------------------------------------- */
  prepareCharacValues(charac) {
    if (charac.label == "OCV" || charac.label == "OMCV" ) {
      charac.total = charac.value
      charac.roll = 11 + charac.value
    } else {
      charac.total = charac.value
      charac.roll = 9 + Math.round((charac.value) / 5)  
    }
  }
  prepareCharac() {
    let characs = duplicate(this.system.characteristics)
    for (let key in characs) {
      let ch = characs[key]
      this.prepareCharacValues(ch)
      if (key == "str") {
        ch.lift = Hero6LiftDice.getLift(ch.value)
        ch.liftDice = Hero6LiftDice.getLiftDice(ch.value)
      }
      if (key == "spd") {
        ch.phasesString = this.getPhasesString()
      }
      if (key == "pre") {
        ch.presenceattack = duplicate(this.system.biodata.presenceattack)
      }
    }
    return characs
  }

  /* -------------------------------------------- */
  getOneSkill(skillId) {
    let skill = this.items.find(item => item.type == 'skill' && item.id == skillId)
    if (skill) {
      skill = duplicate(skill);
    }
    return skill;
  }

  /* -------------------------------------------- */
  computeSTREND() {
    let newSTREND = 0
    switch (this.system.characteristics.str.strendmode) {
      case "str20":
        newSTREND = Math.floor(this.system.characteristics.str.value / 20)
        break;
      case "str10":
        newSTREND = Math.floor(this.system.characteristics.str.value / 10)
        break;
      case "str5":
        newSTREND = Math.floor(this.system.characteristics.str.value / 5)
        break;
    }
    return newSTREND
  }
  /* -------------------------------------------- */
  async deleteAllItemsByType(itemType) {
    let items = this.items.filter(item => item.type == itemType);
    await this.deleteEmbeddedDocuments('Item', items);
  }

  /* -------------------------------------------- */
  async addItemWithoutDuplicate(newItem) {
    let item = this.items.find(item => item.type == newItem.type && item.name.toLowerCase() == newItem.name.toLowerCase())
    if (!item) {
      await this.createEmbeddedDocuments('Item', [newItem]);
    }
  }

  /* -------------------------------------------- */
  async incDecQuantity(objetId, incDec = 0) {
    let objetQ = this.items.get(objetId)
    if (objetQ) {
      let newQ = objetQ.system.quantity + incDec
      if (newQ >= 0) {
        const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'system.quantity': newQ }]) // pdates one EmbeddedEntity
      }
    }
  }
  /* -------------------------------------------- */
  async incDecAmmo(objetId, incDec = 0) {
    let objetQ = this.items.get(objetId)
    if (objetQ) {
      let newQ = objetQ.system.ammocurrent + incDec;
      if (newQ >= 0 && newQ <= objetQ.system.ammomax) {
        const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'system.ammocurrent': newQ }]); // pdates one EmbeddedEntity
      }
    }
  }

  /* -------------------------------------------- */
  getCommonRollData(chKey = undefined) {
    let rollData = Hero6Utility.getBasicRollData()
    rollData.alias = this.name
    rollData.actorImg = this.img
    rollData.actorId = this.id
    rollData.img = this.img
    if (chKey) {
      rollData.charac = duplicate(this.system.characteristics[chKey])
      this.prepareCharacValues(rollData.charac)
    }
    if (rollData.defenderTokenId) {
      let defenderToken = game.canvas.tokens.get(rollData.defenderTokenId)
      let defender = defenderToken.actor

      // Distance management
      let token = this.token
      if (!token) {
        let tokens = this.getActiveTokens()
        token = tokens[0]
      }
      if (token) {
        const ray = new Ray(token.object?.center || token.center, defenderToken.center)
        rollData.tokensDistance = canvas.grid.measureDistances([{ ray }], { gridSpaces: false })[0] / canvas.grid.grid.options.dimensions.distance
      } else {
        ui.notifications.info("No token connected to this actor, unable to compute distance.")
        return
      }
      if (defender) {
        rollData.forceAdvantage = defender.isAttackerAdvantage()
        rollData.advantageFromTarget = true
      }
    }
    console.log("ROLLDATA", rollData)

    return rollData
  }
  /* -------------------------------------------- */
  rollPerception() {
    let rollData = this.getCommonRollData("int")
    rollData.isPerception = true
    rollData.charac.roll = Number(rollData.charac.perceptionroll)
    rollData.mode = "perception"
    if (rollData.target) {
      ui.notifications.warn("You are targetting a token with a skill : please use a Weapon instead.")
      return
    }
    this.startRoll(rollData)
  }

  /* -------------------------------------------- */
  rollCharac(chKey) {
    let rollData = this.getCommonRollData(chKey)
    rollData.mode = "charac"
    if (rollData.target) {
      ui.notifications.warn("You are targetting a token with a skill : please use a Weapon instead.")
      return
    }
    this.startRoll(rollData)
  }
  /* -------------------------------------------- */
  rollItem(itemId) {
    let item = this.items.get(itemId)
    let rollData = this.getCommonRollData()
    rollData.mode = "item"
    rollData.item = duplicate(item)
    if (item.type == "skill") {
      this.prepareSkill(rollData.item)
    }
    if (item.type == "maneuver") {
      this.prepareManeuver(rollData.item)
    }
    this.startRoll(rollData)
  }
  /* -------------------------------------------- */
  async rollDamage(itemId) {
    let item = this.items.get(itemId)
    let rollData = this.getCommonRollData()
    rollData.mode = "damage"
    rollData.item = duplicate(item)
    rollData.title = item.name
    rollData.diceFormula = Hero6Utility.convertRollHeroSyntax(item.system.damage)
    let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
    await Hero6Utility.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))

    rollData.roll = myRoll
    rollData.result = myRoll.total
    rollData.bodyValue = Hero6Utility.computeBodyValue(myRoll)

    let msgFlavor = await renderTemplate(`systems/fvtt-hero-system-6/templates/chat/chat-damage-result.hbs`, rollData)
    let msg = await rollData.roll.toMessage({
      user: game.user.id,
      rollMode: game.settings.get("core", "rollMode"),
      flavor: msgFlavor
    })
    rollData.roll = duplicate(rollData.roll) // Convert to object
    msg.setFlag("world", "rolldata", rollData)
    console.log("Rolldata result", rollData)
  }

  /* -------------------------------------------- */
  async rollLiftDice() {
    let rollData = this.getCommonRollData()
    rollData.mode = "lift-dice"
    rollData.diceFormula = Hero6Utility.convertRollHeroSyntax(Hero6LiftDice.getLiftDice(this.system.characteristics.str.value))
    let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
    await Hero6Utility.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))

    rollData.bodyValue = Hero6Utility.computeBodyValue(myRoll)
    rollData.result = myRoll.total
    rollData.roll = duplicate(myRoll)

    let msgFlavor = await renderTemplate(`systems/fvtt-hero-system-6/templates/chat/chat-lift-dice-result.hbs`, rollData)
    let msg = await myRoll.toMessage({
      user: game.user.id,
      rollMode: game.settings.get("core", "rollMode"),
      flavor: msgFlavor
    })
    msg.setFlag("world", "rolldata", rollData)
    console.log("Rolldata result", rollData)
  }
  /* -------------------------------------------- */
  rollManeuver(maneuverId) {
    let skill = this.items.get(maneuverId)
    if (skill) {
      if (skill.system.islore && skill.system.level == 0) {
        ui.notifications.warn("You can't use Lore Skills with a SL of 0.")
        return
      }
      skill = duplicate(skill)
      Hero6Utility.updateSkill(skill)
      let abilityKey = skill.system.ability
      let rollData = this.getCommonRollData(abilityKey)
      rollData.mode = "skill"
      rollData.skill = skill
      rollData.img = skill.img
      if (rollData.target) {
        ui.notifications.warn("You are targetting a token with a skill : please use a Weapon instead.")
        return
      }
      this.startRoll(rollData)
    }
  }
  /* -------------------------------------------- */
  rollSkill(skillId) {
    let skill = this.items.get(skillId)
    if (skill) {
      if (skill.system.islore && skill.system.level == 0) {
        ui.notifications.warn("You can't use Lore Skills with a SL of 0.")
        return
      }
      skill = duplicate(skill)
      Hero6Utility.updateSkill(skill)
      let abilityKey = skill.system.ability
      let rollData = this.getCommonRollData(abilityKey)
      rollData.mode = "skill"
      rollData.skill = skill
      rollData.img = skill.img
      if (rollData.target) {
        ui.notifications.warn("You are targetting a token with a skill : please use a Weapon instead.")
        return
      }
      this.startRoll(rollData)
    }
  }

  /* -------------------------------------------- */
  async rollWeapon(weaponId) {
    let weapon = this.items.get(weaponId)
    if (weapon) {
      weapon = duplicate(weapon)
      let rollData = this.getCommonRollData()
      rollData.weaponRoll = 11 + this.system.characteristics.ocv.value + (Number(weapon.system.ocv) || 0)
      rollData.mode = "weapon"
      rollData.weapon = weapon
      rollData.img = weapon.img
      this.startRoll(rollData)
    } else {
      ui.notifications.warn("Unable to find the  weapon " + weapon.name)
    }
  }
  /* -------------------------------------------- */
  rollMentalManeuver(maneuverId) {
    let maneuver = this.items.get(maneuverId)
    if (maneuver) {
      maneuver = duplicate(maneuver)
      let rollData = this.getCommonRollData()
      rollData.maneuverRoll = 11 + this.system.characteristics.omcv.value + (Number(maneuver.system.omcv) || 0)
      rollData.mode = "mentalmaneuver"
      rollData.maneuver = maneuver
      rollData.img = maneuver.img
      this.startRoll(rollData)
    } else {
      ui.notifications.warn("Unable to find the maneuver " + maneuver.name)
    }
  }
  /* -------------------------------------------- */
  rollPowerAttack(powerId ) {
    let power = this.items.get(powerId)
    if (power) {
      power = duplicate(power)
      let rollData = this.getCommonRollData()
      if (power.system.attackvalue == "ocv")  {
        rollData.powerRoll = 11 + this.system.characteristics.ocv.value + (Number(power.system.ocv) || 0)
      } else {
        rollData.powerRoll = 11 + this.system.characteristics.omcv.value + (Number(power.system.omcv) || 0)
      }
      rollData.mode = "powerattack"
      rollData.power = power
      rollData.img = power.img
      this.startRoll(rollData)
    } else {
      ui.notifications.warn("Unable to find  power " + power.name)
    }
  }
  /* -------------------------------------------- */
  async startRoll(rollData) {
    let rollDialog = await Hero6RollDialog.create(this, rollData)
    rollDialog.render(true)
  }

}
