import { Misc } from "../misc.js";
import { PART_APPELMORAL } from "./roll-part-appelmoral.mjs";
import { PART_COMP } from "./roll-part-comp.mjs";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.js";
import { ITEM_TYPES, RDD_CONFIG } from "../constants.js";
import { CARACS } from "../rdd-carac.js";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs";
import { PART_ATTAQUE } from "./roll-part-attaque.mjs";

/* -------------------------------------------- */
export class RollDialogAdapter {

  static async rollDice(rollData, rollTitle) {
    const chances = RollDialogAdapter.computeChances({
      carac: rollData.current.carac.value,
      diff: rollData.current.totaldiff,
      bonus: rollData.current.bonus,
      showDice: rollData.options.showDice,
      rollMode: rollData.current.rollmode.key
    })

    const rolled = await RollDialogAdapter.rollChances(rollData, chances)
    RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle)
    RollDialogAdapter.adjustRollDataForV1(rollData)
    RollDialogAdapter.adjustAttaqueParticuliere(rollData)
    RollDialogAdapter.adjustAttaqueDmg(rollData)
    RollDialogAdapter.adjustDemiSurprise(rollData)
    return rolled
  }

  static computeChances({ carac, diff, bonus, showDice, rollMode }) {
    const chances = foundry.utils.deepClone(RdDResolutionTable.computeChances(carac, diff))
    RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
    chances.showDice = showDice
    chances.rollMode = rollMode
    return chances
  }

  static async rollChances(rollData, chances) {
    const rolled = await RdDResolutionTable.rollChances(chances,
      rollData.current.sign.diviseur,
      rollData.current.resultat)
    rolled.caracValue = rollData.current.carac.value
    rolled.finalLevel = rollData.current.totaldiff
    rolled.bonus = rollData.current.bonus ?? 0
    rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur)
    if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
      rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rolled.caracValue, rolled.roll)
      rolled.ajustementNecessaire = rolled.niveauNecessaire - rolled.finalLevel
    }
    return rolled
  }

  static setRollDataRolled(rollData, rolled, rollTitle) {
    rollData.rolled = rolled
    rollData.choix = rollData.choix ?? {}
    rollData.show = rollData.show ?? {}
    rollData.show.title = rollTitle
  }

  static adjustRollDataForV1(rollData) {
    const rolled = rollData.rolled
    // temporaire pour être homogène roll v1
    rollData.alias = rollData.active.actor.getAlias()
    // pour experience
    rollData.finalLevel = rollData.current.totaldiff
    if (rollData.use == undefined) { rollData.use = {} }
    if (rollData.ajustements == undefined) {
      rollData.ajustements = {}
    }
    rollData.selectedCarac = rollData.active.actor.getCaracByName(rollData.current.carac.key)

    const compKey = rollData.current.comp?.key
    if (compKey) {
      rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp
      rollData.jetResistance = rollData.type.resistance
    }
    if (rollData.type.current == ROLL_TYPE_OEUVRE) {
      const oeuvreKey = rollData.current.oeuvre?.key
      if (rollData.type.current == ROLL_TYPE_OEUVRE && oeuvreKey) {
        const oeuvreCurrent = rollData.current[PART_OEUVRE];
        rollData.oeuvre = oeuvreCurrent.oeuvre
        rollData.art = oeuvreCurrent.art.type
      }
    }
    // pour appel moral
    rollData.diviseurSignificative = rollData.current.sign
    if (rollData.current[PART_APPELMORAL]?.checked) {
      rollData.use.moral = true
    }
    rollData.ajustements = rollData.ajustements.map(a => { return { label: a.label, value: a.value } })
  }

  static adjustDemiSurprise(rollData) {
    if (rollData.active.surprise == 'demi' && rollData.rolled.isPart) {
      RdDResolutionTable.replaceParticuliereDemiSurprise(rollData.rolled)
    }
  }

  static adjustAttaqueDmg(rollData) {
    switch (rollData.type.current) {
      case ROLL_TYPE_ATTAQUE:
        rollData.dmg = RdDBonus.dmgRollV2(rollData, rollData.current.attaque)
        break
      case ROLL_TYPE_DEFENSE:
        rollData.dmg = RdDBonus.dmgRollV2(rollData.attackerRoll, rollData.attackerRoll.current.attaque)
        break
    }
  }


  static adjustAttaqueParticuliere(rollData) {
    if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) {
      return
    }

    const attaque = rollData.current.attaque;
    const choix = []
    const isEmpoignade = attaque.dmg.isEmpoignade
    const isCharge = attaque.tactique == 'charge'
    /* TODO: cas de créatures faisant des lancers, Glou, Glipzouk */
    const isMeleeDiffNegative = (attaque.comp.type == ITEM_TYPES.competencecreature || rollData.current.carac.key == CARACS.MELEE)
      && rollData.current.diff.value < 0

    // force toujours, sauf empoignade
    if (!isEmpoignade) {
      choix.push(RDD_CONFIG.particuliere.force)
    }

    // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
    if (!isCharge && (isEmpoignade || isMeleeDiffNegative)) {
      choix.push(RDD_CONFIG.particuliere.finesse)
    }

    // rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum
    if (!isCharge && !isEmpoignade && isMeleeDiffNegative && attaque.arme.system.rapide) {
      choix.push(RDD_CONFIG.particuliere.rapidite)
    }
    if (choix.length == 1) {
      rollData.particuliere = choix[0].key
    }
    rollData.particulieres = choix
  }

  static mapActionAttaque(attackerRoll) {
    if (attackerRoll.ids) {
      return attackerRoll.current[PART_ATTAQUE]
    }
    const label = attackerRoll.alias + ' ' + attackerRoll.arme.name;
    return {
      // correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque)
      label: label,
      // correspond aux actions d'attaques dans RdDActor.listActionsAttaque
      name: label,
      // action: 'attaque',
      arme: attackerRoll.arme,
      comp: attackerRoll.competence,
      main: RdDItemArme.getMainAttaque(attackerRoll.competence),
      equipe: attackerRoll.arme.system.equipe,
      diff: attackerRoll.diffLibre,
      particuliere: attackerRoll.particuliere,
      tactique: RdDBonus.find(attackerRoll.tactique),
      dmg: attackerRoll.dmg,
    }
  }
}
