/* -------------------------------------------- */
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { TYPES } from "./item.js";

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

/* -------------------------------------------- */
export class RdDEmpoignade {

  /* -------------------------------------------- */
  static init() {
  }

  /* -------------------------------------------- */
  static registerChatCallbacks(html) {
    html.on("click", '.defense-empoignade-cac', event => {
      const chatMessage = ChatUtility.getChatMessage(event);
      const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
      let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
      RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
    });
    html.on("click", '.defense-empoignade-esquive', event => {
      const chatMessage = ChatUtility.getChatMessage(event);
      const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
      let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
      RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
    });
    html.on("click", '.empoignade-poursuivre', event => {
      let attackerId = event.currentTarget.attributes['data-attackerId'].value
      let defenderId = event.currentTarget.attributes['data-defenderId'].value
      RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
    });
    html.on("click", '.empoignade-entrainer-sol', event => {
      const chatMessage = ChatUtility.getChatMessage(event);
      const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
      RdDEmpoignade.entrainerAuSol(rollData)
      ChatUtility.removeChatMessageId(chatMessage.id)
    });
    html.on("click", '.empoignade-projeter-sol', event => {
      const chatMessage = ChatUtility.getChatMessage(event);
      const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
      RdDEmpoignade.projeterAuSol(rollData)
      ChatUtility.removeChatMessageId(chatMessage.id)
    });
    html.on("change", '.empoignade-perte-endurance', event => {
      const chatMessage = ChatUtility.getChatMessage(event);
      const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
      if (event.currentTarget.value && event.currentTarget.value != "none") {
        RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
        ChatUtility.removeChatMessageId(chatMessage.id)
      }
    });
  }

  /* -------------------------------------------- */
  static checkEmpoignadeEnCours(actor) {
    // TODO: autoriser la perception? la comédie/séduction?
    if (RdDEmpoignade.isEmpoignadeEnCours(actor)) {
      ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
      return true;
    }
    return false;
  }

  /* -------------------------------------------- */
  static $storeRollEmpoignade(msg, rollData) {
    RdDEmpoignade.$reduceActorToIds(rollData);
    ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
  }

  static $reduceActorToIds(rollData) {
    rollData.attacker = { id: rollData.attacker.id };
    rollData.defender = { id: rollData.defender.id };
  }

  /* -------------------------------------------- */
  static $readRollEmpoignade(msg) {
    const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
    RdDEmpoignade.$replaceIdsWithActors(rollData);
    return rollData
  }

  static $replaceIdsWithActors(rollData) {
    rollData.attacker = game.actors.get(rollData.attacker.id);
    rollData.defender = game.actors.get(rollData.defender.id);
  }

  /* -------------------------------------------- */
  static isEmpoignadeEnCours(actor) {
    return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0)
  }

  /* -------------------------------------------- */
  static getEmpoignadeById(actor, id) {
    let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id)
    return emp && duplicate(emp) || undefined;
  }

  /* -------------------------------------------- */
  static getEmpoignade(attacker, defender) {
    let emp = attacker.itemTypes[TYPES.empoignade].find(it =>
      (it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
      (it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
    )
    if (emp) {
      return duplicate(emp);
    }
    return undefined;
  }

  /* -------------------------------------------- */
  static getMalusTaille(emp, attacker, defender) {
    // Si pas empoigné, alors 0
    if (emp.system.pointsemp == 0) {
      return 0
    }
    // p135: Malus de -1 par point de taille de différence de taille au delà de 1 (donc -2 pour une différence de 3, ...)
    const diffTaille = attacker.system.carac.taille.value - defender.system.carac.taille.value;
    const diffTailleAbs = Math.abs(diffTaille)
    const signDiff = diffTaille > 0 ? 1 : -1

    if (diffTailleAbs > 2) {
      return signDiff * (diffTailleAbs - 1)
    }
    return 0
  }

  static isActionAutorisee(mode, attacker, defender) {
    const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker;
    if (acting.getUserLevel(game.user) < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
      ui.notifications.warn(`Vous n'êtes pas autorisé à choisir l'action de ${acting.name}`)
      return false;
    }
    return true
  }

  static isActionDefenseur(mode) {
    switch (mode) {
      case "liberer":
      case "contrer-empoigner":
        return true;
    }
    return false;
  }

  /* -------------------------------------------- */
  static async onAttaqueEmpoignade(attacker, defender) {
    if (!RdDEmpoignade.isActionAutorisee("empoigner", attacker, defender)) {
      return
    }
    let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
    const isNouvelle = empoignade == undefined;
    empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
    //console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
    if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
      ChatUtility.createChatWithRollMode(attacker.name, {
        content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
      })
    } else {
      await this.onAttaqueEmpoignadeValidee(attacker, defender)
    }
  }

  /* -------------------------------------------- */
  static async onAttaqueEmpoignadeValidee(attacker, defender) {
    let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
    const isNouvelle = empoignade == undefined;
    empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))

    let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"

    if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
      return
    }

    let rollData = {
      mode, empoignade, attacker, defender,
      isEmpoignade: true,
      competence: attacker.getCompetenceCorpsACorps(),
      selectedCarac: attacker.system.carac.melee,
      malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
    }
    if (attacker.isCreatureEntite()) {
      RdDItemCompetenceCreature.setRollDataCreature(rollData)
    }
    if (empoignade.system.pointsemp >= 2) {
      if (!empoignade.system.ausol) {
        let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.html');
        RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
      }
    } else {
      await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
    }
  }

  /* -------------------------------------------- */
  static async onAttaqueEmpoignadeFromItem(empoignade) {
    let attacker = game.actors.get(empoignade.system.empoigneurid)
    let defender = game.actors.get(empoignade.system.empoigneid)
    await this.onAttaqueEmpoignadeValidee(attacker, defender)
  }

  static async onImmobilisation(attacker, defender, empoignade) {
    const rollData = {
      mode: "immobilise",
      empoignade, attacker, defender,
      isEmpoignade: true,
      competence: attacker.getCompetenceCorpsACorps()
    }
    const msg = await ChatMessage.create({
      whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),
      content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
    })
    RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
  }

  /* -------------------------------------------- */
  static async $rollAttaqueEmpoignade(attacker, rollData, isNouvelle = false) {
    const dialog = await RdDRoll.create(attacker, rollData,
      { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
      {
        name: 'jet-empoignade',
        label: 'Empoigner',
        callbacks: [{ action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, isNouvelle) },]
      });
    dialog.render(true);
  }

  /* -------------------------------------------- */
  static async $onRollEmpoignade(rollData, isNouvelle = false) {
    let attacker = game.actors.get(rollData.attacker.id)
    let defender = game.actors.get(rollData.defender.id)


    if (rollData.rolled.isSuccess && isNouvelle) {
      const objectEmpoignade = rollData.empoignade.toObject();
      // Creer l'empoignade sur attaquant/defenseur
      attacker.creerObjetParMJ(objectEmpoignade);
      defender.creerObjetParMJ(objectEmpoignade);
    }

    rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
    if (rollData.rolled.isPart) {
      rollData.particuliere = "finesse";
    }
    let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
    RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
  }

  /* -------------------------------------------- */
  static async onDefenseEmpoignade(attackerRoll, mode, competenceName = "Corps à corps", carac = "melee") {
    let attacker = game.actors.get(attackerRoll.attacker.id)
    let defender = game.actors.get(attackerRoll.defender.id)
    if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
      return
    }

    let empoignade = this.getEmpoignade(attacker, defender)

    if (!empoignade) {
      ui.notifications.warn("Une erreur s'est produite : Aucune empoignade trouvée !!")
      return
    }

    empoignade = duplicate(empoignade)
    let defenderRoll = {
      mode, attacker, defender, empoignade, attackerRoll,
      diffLibre: attackerRoll.diffLibre,
      attaqueParticuliere: attackerRoll.particuliere,
      competence: defender.getCompetence(competenceName),
      surprise: defender.getSurprise(true),
      carac: defender.system.carac,
      selectedCarac: defender.system.carac[carac],
      malusTaille: RdDEmpoignade.getMalusTaille(empoignade, defender, attacker),
      show: {}
    };
    await RdDEmpoignade.$rollDefenseEmpoignade(defender, defenderRoll);
  }

  /* -------------------------------------------- */
  static async $rollDefenseEmpoignade(defender, defenderRoll) {
    const dialog = await RdDRoll.create(defender, defenderRoll,
      { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-empoignade.html' },
      {
        name: 'empoignade',
        label: 'Contrer',
        callbacks: [
          { action: async (r) => await RdDEmpoignade.$onRollContrerLiberer(r) }
        ]
      }
    );
    dialog.render(true);
  }

  /* -------------------------------------------- */
  static async $onRollContrerLiberer(rollData) {
    let empoignade = rollData.empoignade
    
    if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
      empoignade.system.pointsemp++
      RdDEmpoignade.$updateEtatEmpoignade(empoignade)
    }
    if (rollData.mode == "contrer-liberer" && !rollData.rolled.isSuccess) {
      empoignade.system.pointsemp--
      RdDEmpoignade.$updateEtatEmpoignade(empoignade)
    }
    
    await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
    if (empoignade.system.pointsemp >= 2) {
      let msg = await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-empoignade-entrainer.html');
      RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
    }
  }

  /* -------------------------------------------- */
  static async $updateEtatEmpoignade(empoignade) {
    console.log("UPDATE Empoignade", empoignade)

    let defender = game.actors.get(empoignade.system.empoigneid)
    let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
    let update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
    await defender.updateEmbeddedDocuments('Item', [update])

    let attacker = game.actors.get(empoignade.system.empoigneurid)
    emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
    update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
    await attacker.updateEmbeddedDocuments('Item', [update])
  }

  /* -------------------------------------------- */
  static async $deleteEmpoignade(empoignade) {
    console.log("DELETE Empoignade", empoignade)

    let defender = game.actors.get(empoignade.system.empoigneid)
    let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
    await defender.deleteEmbeddedDocuments('Item', [emp._id])
  }

  /* -------------------------------------------- */
  static async entrainerAuSol(rollData) {
    let attacker = game.actors.get(rollData.attacker.id)
    let defender = game.actors.get(rollData.defender.id)
    if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
      return
    }
    let empoignade = this.getEmpoignade(attacker, defender)

    empoignade.system.ausol = true
    await this.$updateEtatEmpoignade(empoignade)

    await attacker.setEffect(STATUSES.StatusProne, true);
    await defender.setEffect(STATUSES.StatusProne, true);

    let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.html');
    RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
  }

  /* -------------------------------------------- */
  static async projeterAuSol(rollData) {
    let attacker = game.actors.get(rollData.attacker.id)
    let defender = game.actors.get(rollData.defender.id)
    if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
      return
    }
    let empoignade = this.getEmpoignade(attacker, defender)

    await defender.setEffect(STATUSES.StatusProne, true);
    await this.$deleteEmpoignade(empoignade)

    let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-projeter-sol.html');
    RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
  }

  /* -------------------------------------------- */
  static async perteEndurance(rollData, perteMode) {
    let attacker = game.actors.get(rollData.attacker.id)
    let defender = game.actors.get(rollData.defender.id)
    if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
      return
    }
    let empoignade = this.getEmpoignade(attacker, defender)

    //console.log("Perte d'endurance :!!!", perteMode)
    let endValue = defender.system.sante.endurance.value
    if (perteMode == "end0") {
      await defender.santeIncDec("endurance", -endValue);
    }
    if (perteMode == "end1") {
      await defender.santeIncDec("endurance", -(endValue - 1));
    }
    if (perteMode == "endmoitie") {
      await defender.santeIncDec("endurance", -Math.floor(endValue / 2));
    }
    if (perteMode == "endquart") {
      await defender.santeIncDec("endurance", -(3 * Math.floor(endValue / 4)));
    }
    let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
    RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
  }

  /* -------------------------------------------- */
  static async deleteAllEmpoignades() {
    for (let actor of game.actors) {
      let empIds = actor.itemTypes["empoignade"].map(it => it.id)
      await actor.deleteEmbeddedDocuments('Item', empIds)
    }
  }

  /* -------------------------------------------- */
  static async deleteLinkedEmpoignade(actorId, empoignade) {
    let actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
    let actor = game.actors.get(actorDeleteId)
    let emp = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
    if (emp) {
      await actor.deleteEmbeddedDocuments('Item', [emp._id])
    }
  }

  /* -------------------------------------------- */
  static async createEmpoignade(attacker, defender) {
    return await Item.create({
      name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name,
      type: 'empoignade',
      img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
      system: { description: "", empoignadeid: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
    },
      {
        temporary: true
      })
  }
}