import MyriadSystemActorBase from "./base-actor.mjs";

export default class MyriadSystemCharacter extends MyriadSystemActorBase {
  static defineSchema() {
    const fields = foundry.data.fields;
    const requiredInteger = { required: true, nullable: false, integer: true };
    const baseSchema = super.defineSchema();

    // Define characteristics schema
    const characteristicFields = {};
    if (CONFIG.MYRIAD_SYSTEM?.characteristics) {
      for (const [key] of Object.entries(CONFIG.MYRIAD_SYSTEM.characteristics)) {
        characteristicFields[key] = new fields.SchemaField({
          value: new fields.NumberField({ ...requiredInteger, initial: 50, min: 0, max: 100 }),
          max: new fields.NumberField({ ...requiredInteger, initial: 100, min: 0, max: 200 }),
          bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
          malus: new fields.NumberField({ ...requiredInteger, initial: 0 })
        });
      }
    }

    // Override the base health schema with character-specific values
    baseSchema.health = new fields.SchemaField({
      value: new fields.NumberField({ ...requiredInteger, initial: 50, min: 0 }),
      max: new fields.NumberField({ ...requiredInteger, initial: 50, min: 0 }),
      _previousPuissance: new fields.NumberField({ initial: 0 }) // For tracking puissance changes
    });

    // Create a new object that includes both the base schema and our additions
    return foundry.utils.mergeObject(baseSchema, {
      attributes: new fields.SchemaField({
        level: new fields.SchemaField({
          value: new fields.NumberField({ ...requiredInteger, initial: 1 })
        })
      }),
      characteristics: new fields.SchemaField(characteristicFields),
      // XP tracking
      xp: new fields.SchemaField({
        value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }), // Spent XP
        earned: new fields.NumberField({ ...requiredInteger, initial: 20, min: 0 }), // Total earned XP (20 XP initiaux)
        unspent: new fields.NumberField({ ...requiredInteger, initial: 20, min: 0 }), // Calculated field: earned - spent
        tempPool: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) // Réserve temporaire pour réallocation
      }),
      // Inventory system
      inventory: new fields.SchemaField({
        grid: new fields.SchemaField({
          width: new fields.NumberField({ ...requiredInteger, initial: 6, min: 1 }),
          height: new fields.NumberField({ ...requiredInteger, initial: 6, min: 1 }),
          additionalCases: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
        }),
        equipped: new fields.ArrayField(new fields.StringField())
      }),
      // Magic points
      magicPoints: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
      // Edit mode indicators
      editMode: new fields.SchemaField({
        active: new fields.BooleanField({ initial: false }),
        changes: new fields.ArrayField(new fields.ObjectField()),
        xpWarning: new fields.BooleanField({ initial: false })
      })
    });
  }

  prepareDerivedData() {
    super.prepareDerivedData();
    
    // Loop through characteristic scores, and add their modifiers to our sheet output.
    if (this.characteristics) {
      for (let [key, characteristic] of Object.entries(this.characteristics)) {
        // Calculate the modifier using d20 rules.
        characteristic.mod = Math.floor((characteristic.value - 10) / 2);
        // Handle characteristic label localization.
        characteristic.label = game.i18n.localize(CONFIG.MYRIAD_SYSTEM.characteristics?.[key]) ?? key;
        
        // Update max value based on supernaturalTiers
        const tier = this.supernaturalTiers?.[key] || 0;
        characteristic.max = 100 + (tier * 20); // 100 + 20 par palier surhumain
      }
    }

    // Calculate health max based on Puissance + bonus
    if (this.characteristics?.puissance && this.health) {
      const puissanceValue = this.characteristics.puissance.value || 0;
      const puissanceBonus = this.characteristics.puissance.bonus || 0;
      const newMaxHealth = puissanceValue + puissanceBonus;
      
      // Update max health if it has changed
      if (this.health.max !== newMaxHealth) {
        this.health.max = newMaxHealth;
        
        // If current health is higher than new max, adjust it
        if (this.health.value > newMaxHealth) {
          this.health.value = newMaxHealth;
        }
      }
    }

    // Calculate unspent XP
    if (this.xp) {
      this.xp.unspent = Math.max(0, (this.xp.earned || 0) - (this.xp.value || 0));
    }
    
    // Calculate inventory additional cases based on Puissance/5
    if (this.inventory?.grid && this.characteristics?.puissance) {
      const puissanceValue = this.characteristics.puissance.value || 0;
      this.inventory.grid.additionalCases = Math.floor(puissanceValue / 5);
    }
    
    // Calculate magic points
    if (this.parent) {
      this.magicPoints = this.calculateMagicPoints();
    }

    // Calculate Action Points max each round depending on stance if in combat
    if (this.parent && this.actionPoints) {
      // Use global combat lookup because DataModel may not have combatant reference yet
      const inCombat = !!game.combat?.combatants.find(c => c.actor?.id === this.parent.id);
      const stance = this.actionPoints.stance || 'defensive';
      const baseMax = stance === 'aggressive' ? 10 : 5; // default mapping
      this.actionPoints.max = inCombat ? baseMax : 0;
      // If not in combat, reset value to 0 (hidden / inactive)
      if (!inCombat) {
        this.actionPoints.value = 0;
      } else {
        // If value is 0 (e.g., just entered combat) set it to max, else clamp
        if (this.actionPoints.value === 0) this.actionPoints.value = this.actionPoints.max;
        else if (this.actionPoints.value > this.actionPoints.max) this.actionPoints.value = this.actionPoints.max;
      }
    }
  }

  getRollData() {
    const data = {};

    // Copy the characteristic scores to the top level, so that rolls can use
    // formulas like `@puissance.mod + 4`.
    if (this.characteristics) {
      for (let [k, v] of Object.entries(this.characteristics)) {
        data[k] = foundry.utils.deepClone(v);
      }
    }

    data.lvl = this.attributes?.level?.value ?? 0;

    return data;
  }
  
  /**
   * Applique des dégâts temporaires à une caractéristique.
   * Utilise le système d'ActiveEffects pour créer un effet temporaire.
   * 
   * @param {string} characteristic - La caractéristique affectée (puissance, coordination, ingeniosite, perspicacite)
   * @param {number} amount - Le montant des dégâts
   * @param {Object} [options={}] - Options supplémentaires
   * @param {number} [options.duration=10] - La durée en rounds
   * @param {string} [options.reason=""] - La raison des dégâts
   * @returns {Promise<ActiveEffect>} - L'effet créé
   */
  async applyTemporaryDamage(characteristic, amount, options = {}) {
    // Vérifier si le module d'effets est disponible
    if (!game.myriad?.effects?.applyCharacteristicDamage) {
      console.error("Le module d'effets n'est pas disponible");
      return null;
    }
    
    // Utiliser la fonction définie dans le module d'effets
    return game.myriad.effects.applyCharacteristicDamage(this.parent, characteristic, amount, options);
  }
  
  /**
   * Calcule le coût en XP pour modifier une caractéristique.
   * Le coût dépend de la valeur actuelle et du palier maximal.
   * 
   * @param {string} charName - Le nom de la caractéristique
   * @param {number} newValue - La nouvelle valeur souhaitée
   * @returns {number} - Le coût en XP
   */
  calculateCharacteristicCost(charName, newValue) {
    if (!this.characteristics?.[charName]) return 0;
    
    const currentValue = this.characteristics[charName].value;
    const maxTier = this.supernaturalTiers?.[charName] || 0;
    const maxValue = 100 + (maxTier * 20); // 100 + 20 par palier surhumain
    
    let cost = 0;
    let diff = Math.abs(newValue - currentValue);
    
    // Si on réduit la caractéristique, pas de coût
    if (newValue < currentValue) return 0;
    
    // Calcul du coût selon les seuils
    // 2 XP par point jusqu'à (palier max - 40)
    // 3 XP par point jusqu'à (palier max - 20)
    // 4 XP par point au-delà
    
    const tier1Limit = maxValue - 40;
    const tier2Limit = maxValue - 20;
    
    for (let i = currentValue + 1; i <= newValue; i++) {
      if (i <= tier1Limit) {
        cost += 2;
      } else if (i <= tier2Limit) {
        cost += 3;
      } else {
        cost += 4;
      }
    }
    
    return cost;
  }
  
  /**
   * Redistribue les points entre caractéristiques.
   * 
   * @param {string} fromChar - La caractéristique source
   * @param {string} toChar - La caractéristique destination
   * @param {number} amount - Le montant à transférer
   * @returns {Promise<Actor>} - L'acteur mis à jour
   */
  async reallocateCharacteristicPoints(fromChar, toChar, amount) {
    if (!this.characteristics?.[fromChar] || !this.characteristics?.[toChar]) {
      return null;
    }
    
    // Vérifier que la caractéristique source a assez de points
    const fromValue = this.characteristics[fromChar].value;
    if (fromValue < amount + 40) { // Ne pas descendre sous 40
      amount = fromValue - 40;
    }
    
    if (amount <= 0) return null;
    
    // Vérifier que la caractéristique destination ne dépasse pas son maximum
    const toValue = this.characteristics[toChar].value;
    const toMax = this.characteristics[toChar].max;
    if (toValue + amount > toMax) {
      amount = toMax - toValue;
    }
    
    if (amount <= 0) return null;
    
    // Appliquer les changements
    const updates = {
      [`system.characteristics.${fromChar}.value`]: fromValue - amount,
      [`system.characteristics.${toChar}.value`]: toValue + amount
    };
    
    return this.parent.update(updates);
  }
  
  /**
   * Calcule les points de magie basés sur les arts et les caractéristiques.
   * Les points de magie = somme des (2 × dizaines de la caractéristique) pour chaque art possédé.
   * 
   * @returns {number} - Le total de points de magie
   */
  calculateMagicPoints() {
    let totalPoints = 0;
    
    // Trouver tous les arts possédés par le personnage
    const arts = this.parent.items.filter(i => i.type === "art");
    
    // Pour chaque art, ajouter les points de magie basés sur la caractéristique liée
    for (const art of arts) {
      const linkedChar = art.system?.linkedCharacteristic;
      if (linkedChar && this.characteristics?.[linkedChar]) {
        const charValue = this.characteristics[linkedChar].value;
        const tens = Math.floor(charValue / 10);
        totalPoints += tens * 2;
      }
    }
    
    return totalPoints;
  }
}