/**
 * DataModel pour les acteurs de type "group" (groupe).
 * Étend foundry.abstract.TypeDataModel.
 */
import {
  woundSchema,
  combatStatusSchema,
  equipmentSchema,
  attributeSchema,
  levelSchema
} from "./_shared.mjs"

export default class VermineGroupData extends foundry.abstract.TypeDataModel {

  /** @override */
  static LOCALIZATION_PREFIXES = ["VERMINE.group"]

  /** @override */
  static defineSchema() {
    const fields = foundry.data.fields

    return {
      // Blessures (base)
      minorWound: new fields.SchemaField(woundSchema(1, 5)),
      majorWound: new fields.SchemaField(woundSchema(4, 4)),
      deadlyWound: new fields.SchemaField(woundSchema(8, 2)),

      // Statut de combat (base)
      combatStatus: combatStatusSchema(),

      // Identité du groupe
      identity: new fields.SchemaField({
        totem: new fields.StringField({ required: true, nullable: false, initial: "" }),
        profile: new fields.StringField({ required: true, nullable: false, initial: "" }),
        origin: new fields.StringField({ required: true, nullable: false, initial: "" }),
        theme: new fields.StringField({ required: true, nullable: false, initial: "" }),
        instincts: new fields.StringField({ required: true, nullable: false, initial: "" }),
        prohibits: new fields.StringField({ required: true, nullable: false, initial: "" }),
        notes: new fields.HTMLField({ required: true, initial: "" })
      }),

      // Équipement
      equipment: equipmentSchema(),

      // Notes de voyage (lieux, dangers, routes…)
      roadNotes: new fields.HTMLField({ required: true, initial: "" }),

      // Niveau du groupe (1-10)
      level: levelSchema(1, 1, 10),

      // Réputation
      reputation: new fields.SchemaField({
        value: new fields.NumberField({ required: true, nullable: true, integer: true, initial: 10, min: 2 }),
        min: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }),
        max: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 10, min: 0 })
      }),

      // Moral
      morale: new fields.SchemaField({
        level: new fields.StringField({ required: true, nullable: false, initial: "high" }),
        value: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 7, min: 0, max: 7 }),
        min: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }),
        max: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 7, min: 0 })
      }),

      // Réserve
      reserve: attributeSchema(0, 0, 10),

      // Objectifs (majeurs et mineurs)
      objectives: new fields.SchemaField({
        major: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })),
        minor: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" }))
      }),

      // Capacités de groupe
      groupAbilities: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })),

      // Membres (IDs d'acteurs)
      members: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })),

      // Dés d'Expérience collectifs (réserve de Groupe)
      experience: new fields.SchemaField({
        dice: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }),
        phase: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }),
        // Limites d'apprentissage par phase
        learned: new fields.SchemaField({
          phase: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }),
          level: new fields.BooleanField({ required: true, initial: false }),
          reserve: new fields.BooleanField({ required: true, initial: false }),
          ability: new fields.BooleanField({ required: true, initial: false })
        })
      }),

      // Rencontres
      encounters: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" }))
    }
  }

  /** @override */
  prepareDerivedData() {
    super.prepareDerivedData()

    // 1. Initialiser les données de groupe si absentes
    this._initGroupData()

    // 2. Calculer la réserve max selon le niveau
    this._calculateGroupReserve()

    // 3. Mettre à jour le moral selon la valeur de dés
    this._updateGroupMorale()

    // 4. Mettre à jour le statut de combat
    this._updateCombatStatus()
  }

  /**
   * Initialise les champs optionnels du groupe s'ils ne sont pas présents.
   */
  _initGroupData() {
    if (!this.objectives) {
      this.objectives = { major: [], minor: [] }
    }
    if (!this.groupAbilities) {
      this.groupAbilities = []
    }
    if (!this.reserve) {
      this.reserve = { value: 0, min: 0, max: 10 }
    }
  }

  /**
   * Calcule la réserve max selon le nombre de membres (personnages).
   * Règles p. 68-69 : la Réserve débute à 3D et gagne 1D par personnage,
   * avec un maximum de 10D.
   */
  _calculateGroupReserve() {
    const members = Array.isArray(this.members) ? this.members : []
    const characterCount = members.filter((id) => game.actors?.get(id)?.type === "character").length
    this.reserve.max = Math.min(10, 3 + characterCount)

    if (this.reserve.value > this.reserve.max) {
      this.reserve.value = this.reserve.max
    }
  }

  /**
   * Met à jour le niveau de moral en fonction de la valeur de dés.
   * Règles : 7D+ = Haut, 6-3D = Normal, 2-1D = Bas, 0D = Crise.
   */
  _updateGroupMorale() {
    const moraleValue = this.morale?.value || 0

    // Ne pas écraser un niveau explicitement défini (sauf "high" qui est la valeur par défaut)
    if (this.morale.level && this.morale.level !== "high") return

    if (moraleValue >= 7) {
      this.morale.level = "high"
    } else if (moraleValue >= 3) {
      this.morale.level = "normal"
    } else if (moraleValue >= 1) {
      this.morale.level = "low"
    } else {
      this.morale.level = "crisis"
    }
  }

  /**
   * Met à jour le label du statut de combat en fonction de la difficulté.
   */
  _updateCombatStatus() {
    const difficulty = parseInt(this.combatStatus.difficulty) || 9
    let newLabel = "Passif"
    switch (difficulty) {
      case 5: newLabel = "Offensif"; break
      case 7: newLabel = "Actif"; break
      case 9: newLabel = "Passif"; break
    }
    if (this.combatStatus.label !== newLabel) {
      this.combatStatus.label = newLabel
    }
  }
}
