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

/* -------------------------------------------- */
/*  Actor Data Models                           */
/* -------------------------------------------- */

function statField() {
  return new SchemaField({
    value: new NumberField({
      required: true, integer: true, min: 1, max: 99, initial: 50, nullable: false
    }),
    descriptor: new StringField({ required: true, blank: true, initial: "" })
  });
}

function stressMeterField() {
  return new SchemaField({
    hardened: new NumberField({ required: true, integer: true, min: 0, max: 10, initial: 0 }),
    failed:   new NumberField({ required: true, integer: true, min: 0, max: 5, initial: 0 })
  });
}

export class CharacterDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      /* ---- Core Stats ---- */
      stats: new SchemaField({
        body:  statField(),
        speed: statField(),
        mind:  statField(),
        soul:  statField()
      }),

      /* ---- Wound Points: max mirrors body.value ---- */
      woundPoints: new SchemaField({
        value: new NumberField({ required: true, integer: true, min: 0, initial: 50, nullable: false }),
        max:   new NumberField({ required: true, integer: true, min: 0, initial: 50, nullable: false })
      }),

      /* ---- Stress Meters ---- */
      stressMeters: new SchemaField({
        violence:    stressMeterField(),
        unnatural:   stressMeterField(),
        helplessness: stressMeterField(),
        isolation:   stressMeterField(),
        self:        stressMeterField()
      }),

      /* ---- Passions ---- */
      passions: new SchemaField({
        fear:  new StringField({ required: true, blank: true, initial: "" }),
        noble: new StringField({ required: true, blank: true, initial: "" }),
        rage:  new StringField({ required: true, blank: true, initial: "" })
      }),

      /* ---- Obsession ---- */
      obsession: new StringField({ required: true, blank: true, initial: "" }),
      obsessionSkillId: new StringField({ required: true, blank: true, initial: "" }),

      /* ---- Character Type Flags ---- */
      isAdept: new BooleanField({ required: true, initial: false }),
      isAvatar: new BooleanField({ required: true, initial: false }),

      /* ---- Campaign Level ---- */
      campaignLevel: new StringField({
        required: true, blank: false,
        choices: ["street", "global", "cosmic"],
        initial: "street"
      }),

      /* ---- Adept Fields ---- */
      adeptTaboo:              new StringField({ required: true, blank: true, initial: "" }),
      adeptChargesMinor:       new NumberField({ required: true, integer: true, min: 0, initial: 0, nullable: false }),
      adeptChargesSignificant: new NumberField({ required: true, integer: true, min: 0, initial: 0, nullable: false }),
      adeptChargesMajor:       new NumberField({ required: true, integer: true, min: 0, initial: 0, nullable: false }),
      adeptChargesHowTo:       new StringField({ required: true, blank: true, initial: "" }),

      /* ---- Avatar Fields ---- */
      avatarPath:        new StringField({ required: true, blank: true, initial: "" }),
      avatarPathSkillId: new StringField({ required: true, blank: true, initial: "" }),
      avatarDescription: new StringField({ required: true, blank: true, initial: "" }),
      avatarTaboo:       new StringField({ required: true, blank: true, initial: "" }),

      /* ---- Background / Notes ---- */
      biography: new HTMLField({ required: true, blank: true, initial: "" }),
      notes:     new HTMLField({ required: true, blank: true, initial: "" })
    };
  }

  static migrateData(source) {
    if (!source.stressMeters && source.madnessMeters) {
      source.stressMeters = source.madnessMeters;
      delete source.madnessMeters;
    }

    if (source.characterType !== undefined) {
      const legacy = source.characterType;
      if (source.isAdept === undefined) source.isAdept = legacy === "adept";
      if (source.isAvatar === undefined) source.isAvatar = legacy === "avatar";
      delete source.characterType;
    }

    // Legacy compatibility: avatar path skill previously reused obsession skill
    if (!source.avatarPathSkillId && source.obsessionSkillId) {
      source.avatarPathSkillId = source.obsessionSkillId;
    }

    return super.migrateData(source);
  }

  prepareDerivedData() {
    super.prepareDerivedData();
    // Keep wound point max in sync with Body score
    this.woundPoints.max = this.stats.body.value;
    // Clamp wound points between 0 and max
    this.woundPoints.value = Math.clamp(this.woundPoints.value, 0, this.woundPoints.max);
  }

  get maxSkillRating() {
    const caps = { street: 55, global: 70, cosmic: 85 };
    return caps[this.campaignLevel] ?? 55;
  }
}

/* -------------------------------------------- */
/*  Item Data Models                            */
/* -------------------------------------------- */

export class SkillDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      stat: new StringField({
        required: true, blank: false,
        choices: ["body", "speed", "mind", "soul"],
        initial: "body"
      }),
      value: new NumberField({
        required: true, integer: true, min: 1, max: 99, initial: 15, nullable: false
      }),
      isObsession: new BooleanField({ required: true, initial: false }),
      isFree:      new BooleanField({ required: true, initial: false }),
      notes:       new StringField({ required: true, blank: true, initial: "" })
    };
  }
}

export class GearDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      category: new StringField({
        required: true, blank: false,
        choices: ["general", "weapon"],
        initial: "general"
      }),
      weaponMode: new StringField({
        required: true, blank: false,
        choices: ["firearm", "melee"],
        initial: "firearm"
      }),
      maxDamage: new NumberField({
        required: true, integer: true, min: 1, max: 100, initial: 50, nullable: false
      }),
      weaponBonus: new NumberField({
        required: true, integer: true, min: 0, max: 30, initial: 3, nullable: false
      }),
      damage: new StringField({ required: true, blank: true, initial: "" }),
      armorPiercing: new BooleanField({ required: true, initial: false }),
      description:   new StringField({ required: true, blank: true, initial: "" }),
      notes:         new StringField({ required: true, blank: true, initial: "" })
    };
  }
}

export class WeaponDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      category: new StringField({
        required: true, blank: false,
        choices: ["general", "weapon"],
        initial: "weapon"
      }),
      weaponMode: new StringField({
        required: true, blank: false,
        choices: ["firearm", "melee"],
        initial: "firearm"
      }),
      maxDamage: new NumberField({
        required: true, integer: true, min: 1, max: 100, initial: 50, nullable: false
      }),
      weaponBonus: new NumberField({
        required: true, integer: true, min: 0, max: 30, initial: 3, nullable: false
      }),
      damage: new StringField({ required: true, blank: true, initial: "1d10" }),
      armorPiercing: new BooleanField({ required: true, initial: false }),
      description:   new StringField({ required: true, blank: true, initial: "" }),
      notes:         new StringField({ required: true, blank: true, initial: "" })
    };
  }
}

export class StrangenessDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      strangenessType: new StringField({
        required: true, blank: false,
        choices: ["magick", "avatar"],
        initial: "magick"
      }),
      school:      new StringField({ required: true, blank: true, initial: "" }),
      value:       new NumberField({
        required: true, integer: true, min: 1, max: 99, initial: 15, nullable: false
      }),
      description: new HTMLField({ required: true, blank: true, initial: "" })
    };
  }
}

/* -------------------------------------------- */
/*  Spell Item (Adept)                          */
/* -------------------------------------------- */

export class SpellDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      chargeType:   new StringField({
        required: true, blank: false,
        choices: ["minor", "significant", "major"],
        initial: "minor"
      }),
      chargeAmount: new NumberField({
        required: true, integer: true, min: 1, max: 10, initial: 1, nullable: false
      }),
      costLabel:    new StringField({ required: true, blank: true, initial: "" }),
      effect:       new HTMLField({ required: true, blank: true, initial: "" })
    };
  }
}

/* -------------------------------------------- */
/*  Avatar Channel Item                         */
/* -------------------------------------------- */

export class AvatarChannelDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      minSkill:    new NumberField({
        required: true, integer: true, min: 0, max: 99, initial: 1, nullable: false
      }),
      description: new HTMLField({ required: true, blank: true, initial: "" })
    };
  }
}

export class StressAfflictionDataModel extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    return {
      meter: new StringField({
        required: true, blank: false,
        choices: ["violence", "unnatural", "helplessness", "isolation", "self"],
        initial: "self"
      }),
      severity: new NumberField({
        required: true, integer: true, min: 1, max: 10, initial: 1, nullable: false
      }),
      ongoing: new BooleanField({ required: true, initial: true }),
      description: new HTMLField({ required: true, blank: true, initial: "" })
    };
  }
}
