import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { ATTAQUE_TYPE } from "../item/arme.js"
import { Misc } from "../misc.js"

export class Distance {

  static typeAttaqueDistance(attaque) {
    function mapTypeAttaque(value) {
      switch (value) {
        case ATTAQUE_TYPE.LANCER: case 'lancer': return ATTAQUE_TYPE.LANCER
        case ATTAQUE_TYPE.TIR: case 'tir': return ATTAQUE_TYPE.TIR
      }
      return undefined
    }
    switch (attaque.comp?.type) {
      case ITEM_TYPES.competence: return mapTypeAttaque(attaque.main)
      case ITEM_TYPES.competencecreature: return mapTypeAttaque(attaque.arme.system.categorie)
    }
    return undefined
  }

  static ajustements(token, defenderToken, attaque) {
    const typeAttaque = Distance.typeAttaqueDistance(attaque)
    if (typeAttaque) {
      const distance = Distance.distance(token, defenderToken)
      const isVisible = Distance.isVisible(token, defenderToken)
      const portee = Distance.ajustementPortee(distance, attaque.arme)
      const taille = Distance.ajustementTaille(defenderToken?.actor)
      const activite = Distance.ajustementMouvement(defenderToken)
      const total = Distance.diff(portee, taille, activite)
      const diffDefense = Distance.ajustementDefense(attaque)
      return { typeAttaque, isVisible, distance, portee, taille, activite, total, diffDefense }
    }
    return undefined
  }

  static distance(token, defenderToken) {
    if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) {
      const source = token.getCenterPoint()
      const target = defenderToken.getCenterPoint()
      const measure = canvas?.grid?.measurePath([ source, target])
      return measure.distance
    }
    return -1 /* distance indéterminée */
  }

  static isVisible(token, defenderToken) {
    // TODO: regarder les StatusEffect aveuglé?
    if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) {
      return canvas?.visibility?.testVisibility(defenderToken.getCenterPoint(), { object: token })
    }
    return true
  }

  static ajustementPortee(distance, arme) {
    if (distance < 0 || !arme) {
      return { msg: "non déterminée", diff: 0 };
    }
    if (arme.system.portee_courte && distance <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
    if (arme.system.portee_moyenne && distance <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
    if (arme.system.portee_extreme && distance <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
    return { msg: "inatteignable", diff: -10 };
  }

  static ajustementTaille(actor) {
    if (!actor) {
      return { msg: "non déterminée", diff: 0 };
    }
    if (actor.isVehicule()) return { msg: "véhicule", diff: 0 }
    const taille = actor.getCaracByName('TAILLE')?.value ?? 1;
    if (taille <= 1) return { msg: "souris", diff: -8 };
    if (taille <= 3) return { msg: "chat", diff: -4 };
    if (taille <= 5) return { msg: "chien", diff: -2 };
    if (taille <= 15) return { msg: "humanoïde", diff: 0 };
    if (taille <= 20) return { msg: "ogre", diff: 2 };
    return { msg: "gigantesque", diff: 4 };
  }

  static ajustementMouvement(defenderToken) {
    if (Distance.$isToken(defenderToken)) {
      if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 };
      if (defenderToken.inCombat) return { msg: "en combat", diff: -4 };
    }
    return { msg: "à déterminer", diff: -3 };
  }

  static diff(...ajustements) {
    return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
  }

  static ajustementDefense(attaque) {
    switch (Grammar.toLowerCaseNoAccentNoSpace(attaque.comp.name)) {
      case 'arbalete': return { label: 'Parade carreau', value: -5 }
      case 'arc': return { label: 'Parade flêche', value: -5 }
      case 'fronde': return { label: 'Parade bille de fronde', value: -4 }
      case 'daguedejet': return { label: 'Parade/Esquive dague lancée', value: -2 }
      case 'javelot': return { label: 'Parade/Esquive javelot lancé', value: -2 }
      case 'fouet': return { label: 'Parade/Esquive fouet', value: 0 }
    }
    return { label: 'Parade/esquive projectile', value: 0 }
  }

  static ajustementBouclier(bouclier) {
    if (bouclier?.system.categorie_parade == 'boucliers') {
      if (bouclier.system.force < 10) {
        return { label: 'Bouclier léger', value: -3 }
      }
      if (bouclier.system.force < 12) {
        return { label: 'Bouclier moyen', value: 0 }
      }
      return { label: 'Bouclier lourd', value: 3 }
    }
    /* esquive */
    return undefined
  }

  static $isToken(token) {
    return token instanceof foundry.canvas.placeables.Token || token instanceof TokenDocument
  }

}