import { Distance } from "../combat/distance.mjs"
import { ITEM_TYPES } from "../constants.js"
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
import { CARACS } from "../rdd-carac.js"
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { PART_SIGN } from "./roll-part-sign.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"

export const PART_DEFENSE = 'defense'

export class RollPartDefense extends RollPartSelect {

  get code() { return PART_DEFENSE }
  get section() { return ROLLDIALOG_SECTION.CHOIX }

  get rollTypes() { return [ROLL_TYPE_DEFENSE] }
  isValid(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined }
  visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_DEFENSE) && rollData.attackerRoll != undefined }

  loadRefs(rollData) {
    const refs = this.getRefs(rollData)
    const attackerRoll = rollData.attackerRoll
    const defenseur = rollData.active.actor
    refs.distance = rollData.attackerRoll.current?.attaque?.distance
    const isEmpoignade = attackerRoll.dmg.isEmpoignade
    const isEmpoignadeEnCours = isEmpoignade && defenseur.itemTypes[ITEM_TYPES.empoignade].find(it =>
      [it.system.empoigneurid, it.system.empoigneid].includes(rollData.ids.opponentId) &&
      it.system.pointsemp != 0)

    const esquives = (refs.distance?.typeAttaque == ATTAQUE_TYPE.TIR || isEmpoignadeEnCours)
      ? []
      : defenseur.getCompetencesEsquive()
    const parades = isEmpoignade
      ? [RdDItemArme.empoignade(defenseur)]
      : this.$getParades(defenseur, attackerRoll, refs.distance)

    refs.defenses = [
      ...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur, attackerRoll)),
      ...parades.map(it => RollPartDefense.$extractParade(it, defenseur, attackerRoll))
    ]
    this.$selectDefense(rollData)
  }

  $getParades(defenseur, attackerRoll, distance) {
    const parades = defenseur.items.filter(it => it.isParade() && (!distance || it.isBouclier()))
    const armeAttaque = attackerRoll?.current?.attaque?.arme
    return armeAttaque
      ? parades.filter(armeDefense => RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) != 'impossible')
      : parades
  }

  static $extractEsquive(esquive, defenseur, attackerRoll) {
    const defense = {
      key: esquive.id,
      label: esquive.name,
      img: esquive.img,
      // TODO: carac pour créatures à vérifier
      carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name,
      verb: "esquive",
      comp: esquive,
      isEsquive: true
    }
    if (attackerRoll.current?.attaque?.distance) {
      defense.distance = {
        ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque),
      }
    }
    return defense
  }

  static $extractParade(armeDefense, defenseur, attackerRoll) {
    const armeAttaque = attackerRoll?.arme
    const comp = (ITEM_TYPES.competencecreature == armeDefense.type)
      ? armeDefense
      : defenseur.getCompetence(armeDefense.system.competence)
    const defense = {
      key: armeDefense.id,
      label: 'Parade ' + armeDefense.name,
      img: armeDefense.img,
      // TODO: carac pour créatures
      carac: defenseur.isPersonnage() ? CARACS.MELEE : comp.name,
      verb: "pare",
      comp: comp,
      arme: armeDefense,
      forceRequise: armeDefense ? RdDItemArme.valeurMain(armeDefense.system.force ?? 0, RdDItemArme.getMainAttaque(comp)) : 0,
      typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm',
      isEsquive: false
    }
    if (attackerRoll.current?.attaque?.distance) {
      defense.distance = {
        ajustementBouclier: Distance.ajustementBouclier(armeDefense),
        ajustementDefense: Distance.ajustementDefense(attackerRoll.current.attaque),
      }
    }
    return defense
  }

  prepareContext(rollData) {
    // current.dmg = this.$dmgRollV2(rollData, current)
  }

  getAjustements(rollData) {
    return []
  }

  choices(refs) { return refs.defenses }

  $selectDefense(rollData, key) {
    this.selectByKey(rollData, key)
  }

  async _onRender(rollDialog, context, options) {
    const selectDefense = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-defense"]`)

    selectDefense.addEventListener("change", e => {
      const selectOptions = e.currentTarget.options
      const index = selectOptions.selectedIndex
      this.$selectDefense(rollDialog.rollData, selectOptions[index]?.value)
      rollDialog.render()
    })
  }

  impactOtherPart(part, rollData) {
    if (this.visible(rollData)) {
      const refs = this.getRefs(rollData)
      const current = this.getCurrent(rollData)
      switch (part.code) {
        case PART_CARAC: return part.filterCaracs(rollData, refs.defenses.length > 0 ? [current.carac] : ['impossible'])
        case PART_COMP: return part.filterComps(rollData, refs.defenses.length > 0 ? [current.comp?.name] : ['impossible'])
        case PART_DIFF:
          if (!rollData.type.appelChance) {
            return part.setDiff(rollData, this.getDiffDefense(rollData))
          }
          return
        case PART_SIGN: return part.setArme(rollData, this.getArmeDisparate(rollData), current.forceRequise)
      }
    }
    return undefined
  }

  getArmeDisparate(rollData) {
    const armeDefense = this.getCurrent(rollData).arme
    if (armeDefense) {
      const armeAttaque = rollData.attackerRoll?.current.attaque.arme
      return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense)
    }
    return 'norm'
  }

  getDiffDefense(rollData) {
    const refs = this.getRefs(rollData)
    if (refs.distance) {
      const current = this.getCurrent(rollData)
      const diff = (current.distance?.ajustementBouclier?.value ?? 0)
        + (current.distance?.ajustementDefense?.value ?? 0)
      return { diff: diff, type: DIFF.DEFENSE }
    }
    if (rollData.attackerRoll) {
      const attackerRoll = rollData.attackerRoll
      const diff = attackerRoll.v2
        ? attackerRoll.selected.diff.value
        : attackerRoll.diff
      return { diff: diff ?? 0, type: DIFF.DEFENSE }
    }
    return { diff: 0, type: DIFF.LIBRE }
  }
}
