/**
 * Helpers partagés pour les Traits (regles/regles_traits.txt).
 *
 * Centralise la lecture des Traits sur les items (présence, valeur) et les
 * calculs liés aux objets équipés d'un acteur (Lourd, Mobilité, Fétiche…).
 * Consommé par les dialogues de jet (combat, action) et les cartes de chat.
 */
export class VermineTraits {

  /**
   * Présence d'un Trait sur un item.
   * @param {Item|null} item
   * @param {string} key clé du Trait (ex. "lourd")
   * @returns {boolean}
   */
  static hasTrait(item, key) {
    return Boolean(item?.system?.traits?.[key]);
  }

  /**
   * Valeur (n) d'un Trait sur un item (0 si absent ou sans valeur).
   * @param {Item|null} item
   * @param {string} key clé du Trait
   * @returns {number}
   */
  static traitValue(item, key) {
    if (!item?.system?.traits?.[key]) return 0;
    return parseInt(item.system.traits[key]?.value ?? 0, 10) || 0;
  }

  /**
   * Items équipés d'un acteur (armes + protections + objets génériques)
   * possédant un Trait donné.
   * @param {Actor} actor
   * @param {string} traitKey
   * @returns {Item[]}
   */
  static equippedItems(actor, traitKey) {
    if (!actor?.itemTypes) return [];
    return [...actor.itemTypes.weapon || [], ...actor.itemTypes.defense || [], ...actor.itemTypes.item || []]
      .filter(i => i.system?.equipped && this.hasTrait(i, traitKey));
  }

  /**
   * Vigueur de l'acteur : caractéristique pour le personnage, tables pour
   * PNJ (Menace) et créature (computed).
   * @param {Actor} actor
   * @returns {number}
   */
  static vigor(actor) {
    if (!actor?.system) return 0;
    if (actor.type === 'npc') {
      const threat = actor.system?.threat?.value || 1;
      return CONFIG.VERMINE.npcThreatLevels?.[threat]?.vigor || 0;
    }
    if (actor.type === 'creature') return actor.system?.computed?.vigor || 0;
    return actor.system?.abilities?.vigor?.value || 0;
  }

  /**
   * Malus cumulés des objets Lourd (n) équipés dont la Vigueur du porteur
   * est inférieure à (n). Les Malus se cumulent entre objets (règles p. …).
   * @param {Actor} actor
   * @returns {number}
   */
  static lourdMalus(actor) {
    const vigor = this.vigor(actor);
    return this.equippedItems(actor, 'lourd').reduce((sum, item) => {
      const n = this.traitValue(item, 'lourd');
      return sum + (n > 0 && vigor < n ? 1 : 0);
    }, 0);
  }

  /**
   * Handicap de Mobilité total : somme des handicaps des protections équipées
   * qui ne sont pas Maniables (le Trait Maniable annule le Handicap).
   * @param {Actor} actor
   * @returns {number}
   */
  static mobilityHandicap(actor) {
    const defenses = (actor?.itemTypes?.defense || []).filter(d => d.system?.equipped);
    return defenses.reduce((sum, d) => sum + (this.hasTrait(d, 'maniable') ? 0 : (parseInt(d.system?.mobility ?? 0, 10) || 0)), 0);
  }

  /**
   * Note de rappel sur la Mobilité (protections équipées non Maniables),
   * ou null si aucun Handicap de Mobilité.
   * @param {Actor} actor
   * @returns {string|null}
   */
  static mobilityNote(actor) {
    const handicap = this.mobilityHandicap(actor);
    if (handicap <= 0) return null;
    return game.i18n.format('VERMINE.traits_mobility_note', { handicap });
  }

  /**
   * Premier item équipé possédant le Trait Fétiche, ou null.
   * @param {Actor} actor
   * @returns {Item|null}
   */
  static feticheItem(actor) {
    return this.equippedItems(actor, 'fetiche')[0] ?? null;
  }

  /**
   * Nombre d'items équipés avec le Trait Fétiche.
   * @param {Actor} actor
   * @returns {number}
   */
  static feticheCount(actor) {
    return this.equippedItems(actor, 'fetiche').length;
  }
}
