const { ArrayField, BooleanField, NumberField, SchemaField, StringField } = foundry.data.fields;

class MyriadesActorDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      characteristics: new SchemaField({
        puissance: new NumberField({ required: true, integer: true, min: 0, max: 200, initial: 50 }),
        coordination: new NumberField({ required: true, integer: true, min: 0, max: 200, initial: 50 }),
        ingeniosite: new NumberField({ required: true, integer: true, min: 0, max: 200, initial: 50 }),
        perspicacite: new NumberField({ required: true, integer: true, min: 0, max: 200, initial: 50 })
      }),
      resources: new SchemaField({
        health: new SchemaField({
          min: new NumberField({ required: true, integer: true, min: 0, initial: 0 }),
          value: new NumberField({ required: true, integer: true, min: 0, initial: 10 }),
          max: new NumberField({ required: true, integer: true, min: 0, initial: 10 })
        }),
        magic: new SchemaField({
          min: new NumberField({ required: true, integer: true, min: 0, initial: 0 }),
          value: new NumberField({ required: true, integer: true, min: 0, initial: 0 }),
          max: new NumberField({ required: true, integer: true, min: 0, initial: 0 })
        })
      }),
      secondaryModifiers: new SchemaField({
        health: new NumberField({ required: true, integer: true, initial: 0 }),
        magic: new NumberField({ required: true, integer: true, initial: 0 }),
        inventory: new NumberField({ required: true, integer: true, initial: 0 })
      })
    };
  }

  prepareDerivedData() {
    super.prepareDerivedData();

    const { health } = this.resources;
    const puissance = this.characteristics.puissance ?? 0;
    const healthModifier = this.secondaryModifiers.health ?? 0;

    health.max = Math.max(0, puissance + healthModifier);
    health.value = Math.clamp(health.value, health.min, health.max);
  }
}

export class CharacterDataModel extends MyriadesActorDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      progression: new SchemaField({
        creationBudget: new NumberField({ required: true, integer: true, initial: 55 }),
        earnedXp: new NumberField({ required: true, integer: true, initial: 0 }),
        manualSpentAdjustment: new NumberField({ required: true, integer: true, initial: 0 }),
        domainlessBonusXp: new NumberField({ required: true, integer: true, min: 0, initial: 15 })
      }),
      magicCharacteristic: new StringField({
        required: true,
        blank: false,
        options: ["puissance", "coordination", "ingeniosite", "perspicacite"],
        initial: "perspicacite"
      }),
      hasPath: new BooleanField({ required: true, initial: false }),
      options: new SchemaField({
        domainless: new BooleanField({ required: true, initial: false })
      })
    };
  }

  prepareDerivedData() {
    super.prepareDerivedData();

    const { magic } = this.resources;
    const sourceCharacteristic = this.characteristics[this.magicCharacteristic] ?? 0;
    const magicModifier = this.secondaryModifiers.magic ?? 0;
    magic.max = Math.max(0, Math.floor(sourceCharacteristic / 10) * 2 + magicModifier);
    magic.value = Math.clamp(magic.value, magic.min, magic.max);
  }
}

export class NpcDataModel extends MyriadesActorDataModel {
  prepareDerivedData() {
    super.prepareDerivedData();

    const { magic } = this.resources;
    const sourceCharacteristic = this.characteristics.perspicacite ?? 0;
    const magicModifier = this.secondaryModifiers.magic ?? 0;
    magic.max = Math.max(0, Math.floor(sourceCharacteristic / 10) * 2 + magicModifier);
    magic.value = Math.clamp(magic.value, magic.min, magic.max);
  }
}

class MyriadesItemDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      grade: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 1 }),
      description: new StringField({ required: true, blank: true, initial: "" })
    };
  }
}

export class SkillDataModel extends MyriadesItemDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      usesGrades: new BooleanField({ required: true, initial: true }),
      maxGrade: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 5 }),
      isRollable: new BooleanField({ required: true, initial: true }),
      skillType: new StringField({
        required: true,
        blank: false,
        initial: "aptitude",
        options: ["aptitude", "unique", "racial", "path"]
      }),
      linkedCharacteristic: new StringField({
        required: true,
        blank: false,
        initial: "puissance",
        options: ["puissance", "coordination", "ingeniosite", "perspicacite"]
      }),
      skillPointCost: new NumberField({ required: true, integer: true, min: 1, initial: 1 }),
      rollModifier: new NumberField({ required: true, integer: true, initial: 0 }),
      sourcePathId: new StringField({ required: true, blank: true, initial: "" }),
      sourcePathKey: new StringField({ required: true, blank: true, initial: "" })
    };
  }
}
export class SpellDataModel extends MyriadesItemDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      magicCost: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 1 }),
      domain: new StringField({ required: true, blank: true, initial: "" }),
      art: new StringField({ required: true, blank: true, initial: "" })
    };
  }
}

export class PathDataModel extends MyriadesItemDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      xpCost: new NumberField({ required: true, integer: true, min: 0, initial: 5 }),
      bundledSkills: new ArrayField(
        new SchemaField({
          key: new StringField({ required: true, blank: true, initial: "" }),
          name: new StringField({ required: true, blank: false, initial: "Nouvelle compétence" }),
          description: new StringField({ required: true, blank: true, initial: "" }),
          grade: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 1 }),
          usesGrades: new BooleanField({ required: true, initial: true }),
          maxGrade: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 5 }),
          skillType: new StringField({
            required: true,
            blank: false,
            initial: "aptitude",
            options: ["aptitude", "unique", "racial", "path"]
          }),
          linkedCharacteristic: new StringField({
            required: true,
            blank: false,
            initial: "puissance",
            options: ["puissance", "coordination", "ingeniosite", "perspicacite"]
          }),
          isRollable: new BooleanField({ required: true, initial: true }),
          skillPointCost: new NumberField({ required: true, integer: true, min: 1, initial: 1 }),
          rollModifier: new NumberField({ required: true, integer: true, initial: 0 })
        })
      )
    };
  }
}

export class EquipmentDataModel extends MyriadesItemDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      slots: new NumberField({ required: true, integer: true, min: 1, max: 36, initial: 1 }),
      quantity: new NumberField({ required: true, integer: true, min: 1, initial: 1 }),
      width: new NumberField({ required: true, integer: true, min: 1, max: 6, initial: 1 }),
      height: new NumberField({ required: true, integer: true, min: 1, max: 6, initial: 1 }),
      equipped: new BooleanField({ required: true, initial: false }),
      usable: new BooleanField({ required: true, initial: false }),
      equippable: new BooleanField({ required: true, initial: true }),
      magical: new BooleanField({ required: true, initial: false }),
      consumable: new BooleanField({ required: true, initial: false }),
      throwable: new BooleanField({ required: true, initial: false }),
      charges: new SchemaField({
        value: new NumberField({ required: true, integer: true, min: 0, initial: 0 }),
        max: new NumberField({ required: true, integer: true, min: 0, initial: 0 })
      })
    };
  }
}

export class EffectDataModel extends MyriadesItemDataModel {
  static defineSchema() {
    return {
      ...super.defineSchema(),
      enabled: new BooleanField({ required: true, initial: true }),
      modifiers: new ArrayField(
        new SchemaField({
          target: new StringField({
            required: true,
            blank: false,
            initial: "puissance",
            options: [
              "puissance", "coordination", "ingeniosite", "perspicacite",
              "healthMax", "magicMax", "inventoryCapacity"
            ]
          }),
          mode: new StringField({
            required: true,
            blank: false,
            initial: "add",
            options: ["add", "multiply", "override"]
          }),
          value: new NumberField({ required: true, initial: 0 }),
          perGrade: new BooleanField({ required: true, initial: false }),
          grade: new NumberField({ required: true, integer: true, min: 1, max: 5, initial: 1 })
        })
      )
    };
  }
}
