import { RdDBaseActor } from "./actor/base-actor.js";
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Monnaie } from "./item-monnaie.js";
import { ITEM_TYPES, ACTOR_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
import { VOIES_DRACONIC } from "./item-sort.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { APPRECIATION } from "./moral/apprecier.mjs";

class Migration {
  get code() { return "sample"; }
  get version() { return "0.0.0"; }
  async migrate() { }

  async applyItemsUpdates(computeUpdates) {
    await Promise.all(game.actors.map(actor => {
      const actorItemUpdates = computeUpdates(actor.items).filter(it => it != undefined);
      if (actorItemUpdates.length > 0) {
        console.log(this.code, `Applying updates on actor ${actor.name} items`, actorItemUpdates);
        return actor.updateEmbeddedDocuments("Item", actorItemUpdates);
      }
    }))

    const itemUpdates = computeUpdates(game.items).filter(it => it != undefined)
    if (itemUpdates.length > 0) {
      console.log(this.code, "Applying updates on items", itemUpdates)
      await Item.updateDocuments(itemUpdates)
    }
  }
}

class _1_5_34_migrationPngWebp {
  get code() { return "migrationPngWebp"; }
  get version() { return "1.5.34"; }
  async migrate() {

    const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/;
    const replaceWithWebp = '$1.webp';
    function convertImgToWebp(img) {
      return img.replace(regexOldPngJpg, replaceWithWebp);
    }
    function prepareDocumentsImgUpdate(documents) {
      return documents.filter(it => it.img && it.img.match(regexOldPngJpg))
        .map(it => {
          return { _id: it.id, img: convertImgToWebp(it.img) }
        });
    }

    const itemsUpdates = prepareDocumentsImgUpdate(game.items);
    const actorsUpdates = prepareDocumentsImgUpdate(game.actors);
    //Migrate system png to webp
    await Item.updateDocuments(itemsUpdates);
    await Actor.updateDocuments(actorsUpdates);
    await Promise.all(game.actors
      .filter(actor => actor.token?.img && actor.token.img.match(regexOldPngJpg))
      .map(actor => actor.update({ "token.img": convertImgToWebp(actor.token.img) }))
    )
    await Promise.all(game.actors.map(actor =>
      actor.updateEmbeddedDocuments('Item', prepareDocumentsImgUpdate(actor.items))
    ))
  }
}

class _10_0_16_MigrationSortsReserve extends Migration {
  get code() { return "creation-item-sort-reserve"; }
  get version() { return "10.0.16"; }

  async migrate() {
    const actors = game.actors.filter((actor) => actor.type == "personnage" && (actor.system.reve?.reserve?.list?.length ?? 0 > 0))
    await Promise.all(actors.map(async it => await this.convertirSortsReserveActeur(it)))
  }

  async convertirSortsReserveActeur(actor) {
    const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve);
    console.log(`${LOG_HEAD} Migration des sorts en réserve de ${actor.name}`, sortsReserve);
    await actor.createEmbeddedDocuments("Item", sortsReserve, {
      renderSheet: false,
    });
    await actor.update({ 'system.reve.reserve': undefined });
  }

  conversionSortReserve(it) {
    return {
      type: 'sortreserve',
      name: it.sort.name,
      img: it.sort.img,
      system: {
        // ATTENTION, utilisation de data / _id possibles, encore présents pour les anciens sorts en réserve
        sortid: it.sort._id,
        draconic: it.sort.draconic,
        ptreve: (it.sort.system ?? it.sort.data).ptreve_reel,
        coord: it.coord,
        heurecible: 'Vaisseau',
      },
    };
  }
}

class _10_0_17_MigrationCompetenceCreature extends Migration {
  get code() { return "competences-creature-parade"; }
  get version() { return "10.0.17"; }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => it.type == "competencecreature" && it.system.isparade && it.system.categorie_parade == "")
      .map(it => { return { _id: it.id, "system.categorie_parade": "armes-naturelles" } }));

    await this.applyItemsUpdates(items => items
      .filter(it => it.type == "competencecreature" && it.system.iscombat)
      .map(it => { return { _id: it.id, "system.categorie": (Grammar.includesLowerCaseNoAccent(it.name, "lancee") ? "lancer" : "melee") } })
    );

  }
}

class _10_0_21_VehiculeStructureResistanceMax extends Migration {
  get code() { return "vehicule-structure-resistance-max"; }
  get version() { return "10.0.21"; }

  async migrate() {
    await Promise.all(
      game.actors.filter(actor => actor.type == "vehicule")
        .map(actor => actor.update({
          'system.etat.resistance.value': actor.system.resistance,
          'system.etat.resistance.max': actor.system.resistance,
          'system.etat.structure.value': actor.system.structure,
          'system.etat.structure.max': actor.system.structure
        }))
    )
  }
}

class _10_0_33_MigrationNomsDraconic extends Migration {
  get code() { return "competences-nom-draconic"; }
  get version() { return "10.0.33"; }

  migrationNomDraconic(ancien) {
    if (typeof ancien == 'string') {
      switch (ancien) {
        case 'oniros': case "Voie d'Oniros": return "Voie d'Oniros";
        case 'hypnos': case "Voie d'Hypnos": return "Voie d'Hypnos";
        case 'narcos': case "Voie de Narcos": return "Voie de Narcos";
        case 'thanatos': case "Voie de Thanatos": return "Voie de Thanatos";
      }
      return ancien;
    }
    else if (typeof ancien.name == 'string') {
      return this.migrationNomDraconic(ancien.name)
    }
    return ancien;
  }
  async migrate() {

    await this.applyItemsUpdates(items => items
      .filter(it => ["sort", "sortreserve"].includes(it.type)
        && (typeof it.system.draconic == 'string') || (typeof it.system.draconic?.name == 'string'))
      .map(it => { return { _id: it.id, "system.draconic": this.migrationNomDraconic(it.system.draconic) } }));
  }
}

class _10_2_5_ArmesTirLancer extends Migration {
  constructor() {
    super();
    this.dagues = { "system.competence": 'Dague', "system.lancer": 'Dague de jet', "system.portee_courte": 3, "system.portee_moyenne": 8, "system.portee_extreme": 15 }
    this.javelot = { "system.competence": 'Lance', "system.lancer": 'Javelot', "system.portee_courte": 6, "system.portee_moyenne": 12, "system.portee_extreme": 20 }
    this.fouet = { "system.competence": '', "system.lancer": 'Fouet', "system.portee_courte": 2, "system.portee_moyenne": 2, "system.portee_extreme": 3, "system.penetration": -1 }
    this.arc = { "system.competence": '', "system.tir": 'Arc' }
    this.arbalete = { "system.competence": '', "system.tir": 'Arbalète' }
    this.fronde = { "system.competence": '', "system.tir": 'Fronde' }

    this.mappings = {
      'dague': { filter: it => true, updates: this.dagues },
      'dague de jet': { filter: it => true, updates: this.dagues },
      'javelot': { filter: it => true, updates: this.javelot },
      'lance': { filter: it => it.name == 'Javeline', updates: this.javelot },
      'fouet': { filter: it => true, updates: this.fouet },
      'arc': { filter: it => true, updates: this.arc },
      'arbalete': { filter: it => true, updates: this.arbalete },
      'fronde': { filter: it => true, updates: this.fronde },
    }
  }

  get code() { return "separation-competences-tir-lancer"; }
  get version() { return "10.2.5"; }

  migrateArmeTirLancer(it) {
    const updates = foundry.utils.mergeObject({ _id: it.id }, this.getMapping(it).updates)
    console.log(it.name, updates)
    return updates
  }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => "arme" == it.type)
      .filter(it => this.isTirLancer(it))
      .filter(it => this.getMapping(it).filter(it))
      .map(it => this.migrateArmeTirLancer(it)));
  }


  isTirLancer(it) {
    return Object.keys(this.mappings).includes(this.getCompKey(it));
  }

  getMapping(it) {
    return this.mappings[this.getCompKey(it)];
  }

  getCompKey(it) {
    return Grammar.toLowerCaseNoAccent(it.system.competence);
  }
}

class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
  get code() { return "desir-lancinat-idee-fixe"; }
  get version() { return "10.2.10"; }

  migrateQueue(it) {
    let categorie = undefined
    let name = it.name
    if (Grammar.toLowerCaseNoAccent(name).includes('desir')) {
      categorie = 'lancinant';
      name = it.name.replace('Désir lancinant : ', '');

    }
    if (Grammar.toLowerCaseNoAccent(name).includes('idee fixe')) {
      categorie = 'ideefixe';
      name = it.name.replace('Idée fixe : ', '')
    }
    return {
      _id: it.id, name: name,
      'system.ideefixe': undefined,
      'system.lancinant': undefined,
      'system.categorie': categorie
    }
  }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => ['queue', 'ombre'].includes(it.type))
      .map(it => this.migrateQueue(it))
    )
  }
}

class _10_3_0_Inventaire extends Migration {
  get code() { return "migration-equipement-inventaire"; }
  get version() { return "10.3.0"; }

  async migrate() {
    await this.applyItemsUpdates(items => {
      return this._updatesMonnaies(items)
        .concat(this._updatesNonEquipe(items))
        .concat(this._updatesObjets(items))
    });
  }

  _updatesNonEquipe(items) {
    return items
      .filter(it => ['munition'].includes(it.type))
      .map(it => { return { _id: it.id, 'system.equipe': undefined } });
  }
  _updatesObjets(items) {
    return items
      .filter(it => ['objet'].includes(it.type))
      .map(it => { return { _id: it.id, 'system.resistance': undefined, 'system.equipe': undefined } });
  }
  _updatesMonnaies(items) {
    return items
      .filter(it => ['monnaie'].includes(it.type) && it.system.valeur_deniers != undefined)
      .map(it => { return { _id: it.id, 'system.cout': it.system.valeur_deniers / 100, 'system.valeur_deniers': undefined } });
  }
}

class _10_3_0_FrequenceEnvironnement extends Migration {
  get code() { return "migration-frequence-resources"; }
  get version() { return "10.3.0"; }

  async migrate() {
    await this.applyItemsUpdates(items => items.filter(it => ['herbe', 'ingredient'].includes(it.type))
      .map(it => this._updatesFrequences(it)));
  }

  _updatesFrequences(it) {
    const rarete = RdDRaretes.byCode(it.system.rarete);
    return {
      _id: it.id,
      'system.rarete': undefined,
      'system.environnement': [{ milieu: it.system.milieu, rarete: rarete.code, frequence: rarete.frequence }]
    }
  }
}

class _10_3_17_Monnaies extends Migration {
  constructor() {
    super();
    this.mapValeur = {
      "Etain (1 denier)": { name: 'Denier (étain)', system: { cout: 0.01 } },
      "Bronze (10 deniers)": { name: "Sou (bronze)", system: { cout: 0.1 } },
      "Argent (1 sol)": { name: "Sol (argent)", system: { cout: 1 } },
      "Or (10 sols)": { name: "Dragon (or)", system: { cout: 10 } }
    };
  }
  get code() { return "migration-monnaies"; }
  get version() { return "10.3.17"; }

  async migrate() {
    await this.applyItemsUpdates(items => this._updatesMonnaies(items));
  }

  _updatesMonnaies(items) {
    return items
      .filter(it => 'monnaie' == it.type)
      .filter(it => this.mapValeur[it.name] != undefined)
      .map(it => {
        const correction = this.mapValeur[it.name];
        return {
          _id: it.id,
          'name': correction.name,
          'system.cout': correction.system.cout,
          'system.valeur_deniers': undefined
        }
      });
  }
}

class _10_4_6_ServicesEnCommerces extends Migration {

  get code() { return "migration-service-acteurs"; }
  get version() { return "10.4.6"; }

  async migrate() {
    const servicesToMigrate = game.items.filter(it => it.type == 'service');
    servicesToMigrate.forEach(async service => {
      const commerce = await this.convertServiceToCommerce(service);
      await RdDBaseActor.create(commerce, { renderSheet: false });
      await service.delete();
    });
  }

  async convertServiceToCommerce(service) {
    return {
      name: service.name, img: service.img, type: 'commerce',
      system: {
        description: service.system.description,
        notesmj: service.system.descriptionmj,
        illimite: service.system.illimite
      },
      items: await this.transformInventaireCommerce(service)
    }
  }
  async transformInventaireCommerce(service) {
    const serviceItems = (service.system.items ?? []);
    const commerceItems = await Promise.all(serviceItems.map((it) => this.transformToItemBoutique(it)))
    return commerceItems.concat(Monnaie.monnaiesStandard());
  }

  async transformToItemBoutique(serviceRefItem) {
    const item = await RdDItem.getCorrespondingItem(serviceRefItem);
    const itemToCreate = {
      name: item.name, img: item.img, type: item.type,
      system: foundry.utils.mergeObject({ cout: serviceRefItem.system.cout, quantite: serviceRefItem.system.quantite }, item.system, { overwrite: false })
    };
    return itemToCreate;
  }
}

class _10_5_0_UpdatePeriodicite extends Migration {
  get code() { return "migration-periodicite-poisons-maladies"; }
  get version() { return "10.5.0"; }

  async migrate() {
    await this.applyItemsUpdates(items => this._updatePeriodicite(items));
  }

  _updatePeriodicite(items) {
    return items.filter(it => ['poison', 'maladie'].includes(it.type))
      .filter(it => it.system.periodicite != "")
      .map(it => {
        let [incubation, periodicite] = this.getPeriodicite(it);
        const periode = periodicite.split(' ');
        let unite = periode.length == 2
          ? RdDTimestamp.formulesPeriode().find(it => Grammar.includesLowerCaseNoAccent(periode[1], it.code))?.code
          : undefined
        if (unite && Number(periode[0])) {
          return {
            _id: it.id,
            'system.periodicite': undefined,
            'system.incubation': incubation,
            'system.periode.nombre': Number.parseInt(periode[0]),
            'system.periode.unite': unite
          };
        }
        else {
          return {
            _id: it.id,
            'system.periodicite': undefined,
            'system.incubation': it.system.periodicite
          };
        }
      }).filter(it => it != undefined);
  }

  getPeriodicite(it) {
    let p = it.system.periodicite.split(/[\/\\]/);
    switch (p.length) {
      case 2: return [p[0].trim(), p[1].trim()];
      case 1: return ["", it.system.periodicite.trim()];
      default: return [it.system.periodicite.trim(), ""];
    }
  }
}

class _10_7_0_MigrationBlessures extends Migration {
  get code() { return "migration-blessures"; }
  get version() { return "10.7.0"; }

  async migrate() {
    const timestamp = game.system.rdd.calendrier.getTimestamp()
    await Promise.all(game.actors.filter(it => it.isPersonnage() || it.isCreature())
      .map(async (actor) => {
        const legeres = actor.system.blessures?.legeres.liste.filter(it => it.active).map(it => this.creerBlessure(2, 'légère', it, timestamp)) ?? [];
        const graves = actor.system.blessures?.graves.liste.filter(it => it.active).map(it => this.creerBlessure(4, 'grave', it, timestamp)) ?? [];
        const critiques = actor.system.blessures?.critiques.liste.filter(it => it.active).map(it => this.creerBlessure(6, 'critique', it, timestamp));
        const blessures = legeres.concat(graves).concat(critiques);
        if (blessures.length > 0) {
          await actor.createEmbeddedDocuments("Item", blessures);
        }
        await actor.update({
          'system.blessures.legeres.liste': [],
          'system.blessures.graves.liste': [],
          'system.blessures.critiques.liste': []
        })
      }))
  }
  creerBlessure(gravite, graviteTexte, blessure, timestamp) {
    const dateBlessure = timestamp.addJours(-blessure.jours);
    const datePremiereRecup = dateBlessure.addJours(gravite);
    return {
      name: `Blessure ${graviteTexte}`,
      type: 'blessure',
      img: `systems/foundryvtt-reve-de-dragon/icons/sante/blessure${blessure.psdone ? '-soins' : ''}.webp`,
      system: {
        gravite: gravite,
        difficulte: -gravite,
        debut: { indexDate: dateBlessure.indexDate, indexMinute: 0 },
        fin: { indexDate: datePremiereRecup.indexDate, indexMinute: 0 },
        premierssoins: { done: blessure.psdone, bonus: blessure.premiers_soins },
        soinscomplets: { done: blessure.scdone, bonus: blessure.soins_complets },
        localisation: blessure.localisation
      }
    }
  }
}

class _10_7_19_CategorieCompetenceCreature extends Migration {
  get code() { return "categorie-competence-creature"; }
  get version() { return "10.7.19"; }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => ITEM_TYPES.competencecreature == it.type)
      .map(it => this.migrateCompetenceCreature(it))
    );
  }

  migrateCompetenceCreature(it) {
    const categorie = this.getCategorie(it)
    if (categorie == it.system.categorie) {
      return undefined
    }
    return { _id: it.id, 'system.categorie': categorie }
  }

  getCategorie(it) {
    if (it.system.ispossession) {
      return 'possession'
    }
    switch (it.system.categorie) {
      case "melee":
        if (it.system.isnaturelle) {
          return 'naturelle'
        }
        return 'melee'
      case "particuliere": case "specialisee": case "connaissance":
        return "generale"
      default:
        return it.system.categorie
    }
  }
}

class _10_7_19_PossessionsEntiteVictime extends Migration {
  get code() { return "possessions-entite-victime"; }
  get version() { return "10.7.19"; }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => ITEM_TYPES.possession == it.type)
      .map(it => this.migratePossession(it))
    );
  }

  migratePossession(it) {
    return {
      _id: it.id,
      'system.entite.actorid': it.system.possesseurid,
      'system.victime.actorid': it.system.possedeid
    }
  }
}

class _11_2_20_MigrationAstrologie extends Migration {
  get code() { return "migration-astrologie" }
  get version() { return "11.2.20" }

  async migrate() {
    const nombresAstraux = game.system.rdd.calendrier.getNombresAstraux()
    nombresAstraux.forEach(na => {
      na.lectures = na.valeursFausses
      na.valeursFausses = undefined
    })
    await game.system.rdd.calendrier.setNombresAstraux(nombresAstraux)
  }
}

class _12_0_26_MigrationVoieSorts extends Migration {
  get code() { return "migration-voies-sorts" }
  get version() { return "12.0.26" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => [ITEM_TYPES.sort, ITEM_TYPES.sortreserve].includes(it.type))
      .map(it => this.migrateSort(it))
    )
    await this.applyItemsUpdates(items => items
      .filter(it => ITEM_TYPES.competence == it.type && it.system.categorie == 'draconic')
      .map(it => this.migrateDraconic(it))
    )
  }
  migrateDraconic(it) {
    return {
      _id: it.id,
      name: this.convertDraconic(it.name),
    }
  }
  migrateSort(it) {
    return {
      _id: it.id,
      'system.draconic': this.convertDraconic(it.system.draconic),
    }
  }
  convertDraconic(draconic) {
    for (let v of VOIES_DRACONIC) {
      if ([v.label, v.short, v.code].includes(draconic)) {
        return v.short
      }
    }
    return draconic
  }
}

class _12_0_32_MigrationRaces extends Migration {
  get code() { return "migration-races" }
  get version() { return "12.0.32" }

  async migrate() {
    const races = await SystemCompendiums.getItems("races", ITEM_TYPES.race)
    await Promise.all(game.actors.filter(it => it.type == ACTOR_TYPES.personnage).map(async actor => {
      if (actor.itemTypes[ITEM_TYPES.race].length == 0) {
        const raceName = actor.system.race ?? 'Humain'
        const race = races.find(it => Grammar.equalsInsensitive(raceName, it.name))
        if (race) {
          console.log(this.code, `Adding race ${race.name} to actor ${actor.name}`)
          await actor.createEmbeddedDocuments('Item', [race])
          console.log(this.code, `Neutralizing race ${race.name} adjustments for actor ${actor.name}`)
          await actor._applyRaceCaracUpdates(race, -1)
        }
      }
    }))
  }
}

class _12_0_37_MigrationAlchimieEtat extends Migration {
  get code() { return "migration-alchimie-etat" }
  get version() { return "12.0.37" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => [ITEM_TYPES.potion].includes(it.type))
      .map(it => this.migratePotion(it))
    )
  }

  mappingCategorie(categorie) {
    switch (categorie) {
      case 'AlchimieEnchante': return 'Alchimie'
      case 'ReposEnchante': return 'Repos'
      case 'SoinEnchante': return 'Soin'
      case 'AutreEnchante': return 'Autre'
    }
    return categorie
  }

  mappingEtat(categorie) {
    return ['Alchimie', 'Repos', 'Soin', 'Autre'].includes(categorie) ? 'Liquide' : 'Autre'
  }

  migratePotion(potion) {
    const newCategorie = this.mappingCategorie(potion.system.categorie)
    return {
      _id: potion.id,
      'system.etat': this.mappingEtat(potion.system.categorie),
      'system.magique': potion.system.pr > 0,
      'system.categorie': newCategorie
    }
  }
}

class _12_0_38_TachesEcriture extends Migration {
  get code() { return "migration-tache-ecriture" }
  get version() { return "12.0.38" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => [ITEM_TYPES.tache, ITEM_TYPES.livre, ITEM_TYPES.oeuvre, ITEM_TYPES.meditation].includes(it.type))
      .filter(it => Grammar.equalsInsensitive(it.system.competence, 'ecriture'))
      .map(it => { return { _id: it.id, 'system.competence': 'Écriture' } })
    )
  }
}

class _13_0_4_FixReveActuel extends Migration {
  get code() { return "fix-reve-actuel" }
  get version() { return "13.0.4" }

  async migrate() {
    game.actors.forEach(it => it.update({ 'system.carac.-=reve-actuel': null }))
  }
}

class _13_0_7_FixNiveauOeuvres extends Migration {
  get code() { return "fix-niveau-oeuvres" }
  get version() { return "13.0.7" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => [ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.recettecuisine].includes(it.type))
      .map(it => {
        const niveau = isNaN(it.system.niveau) ? 0 : parseInt(it.system.niveau)
        return { _id: it.id, 'system.niveau': niveau }
      })
    )
  }
}

class _13_0_21_AjoutAppreciation extends Migration {
  get code() { return "ajout-appreciation" }
  get version() { return "13.0.21" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => it.isAppreciable())
      .filter(it => this.getBaseAppreciation(it))
      .map(it => {
        return { _id: it.id, 'system.appreciation': this.getBaseAppreciation(it) }
      })
    )
  }

  getBaseAppreciation(item) {
    switch (item.type) {
      case ITEM_TYPES.nourritureboisson: return APPRECIATION.CUISINE
      case ITEM_TYPES.service: return APPRECIATION.SERVICE
      case ITEM_TYPES.musique: return APPRECIATION.MUSIQUE
      case ITEM_TYPES.chant: return APPRECIATION.CHANT
      case ITEM_TYPES.danse: return APPRECIATION.DANSE
      case ITEM_TYPES.oeuvre: {
        const appreciation = foundry.utils.deepClone(APPRECIATION.OEUVRE)
        appreciation.competence = item.system.competence
        return appreciation
      }
    }
    return undefined
  }
}

class _13_0_22_PoidsDesMonnaies extends Migration {
  get code() { return "poid-monnaies" }
  get version() { return "13.0.22" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => it.type == ITEM_TYPES.monnaie)
      .map(it => {
        return { _id: it.id, 'system.encombrement': this.poids(it) }
      })
    )
  }
  poids(monnaie) {
    if (monnaie.system.cout < 0.05) return 0.001
    if (monnaie.system.cout < 0.5) return 0.002
    if (monnaie.system.cout < 5) return 0.003
    return 0.004
  }
}

class _13_0_23_OmbreCategorieFalse extends Migration {
  get code() { return "ombre-categorie-false" }
  get version() { return "13.0.23" }

  async migrate() {
    await this.applyItemsUpdates(items => items
      .filter(it => it.type == ITEM_TYPES.ombre && it.system.categorie === "false")
      .map(it => ({ _id: it.id, 'system.categorie': "" }))
    )
  }
}

export class Migrations {
  static getMigrations() {
    return [
      new _1_5_34_migrationPngWebp(),
      new _10_0_16_MigrationSortsReserve(),
      new _10_0_17_MigrationCompetenceCreature(),
      new _10_0_21_VehiculeStructureResistanceMax(),
      new _10_0_33_MigrationNomsDraconic(),
      new _10_2_5_ArmesTirLancer(),
      new _10_2_10_DesirLancinant_IdeeFixe(),
      new _10_3_0_Inventaire(),
      new _10_3_0_FrequenceEnvironnement(),
      new _10_3_17_Monnaies(),
      new _10_4_6_ServicesEnCommerces(),
      new _10_5_0_UpdatePeriodicite(),
      new _10_7_0_MigrationBlessures(),
      new _10_7_19_CategorieCompetenceCreature(),
      new _10_7_19_PossessionsEntiteVictime(),
      new _11_2_20_MigrationAstrologie(),
      new _12_0_26_MigrationVoieSorts(),
      new _12_0_32_MigrationRaces(),
      new _12_0_37_MigrationAlchimieEtat(),
      new _12_0_38_TachesEcriture(),
      new _13_0_4_FixReveActuel(),
      new _13_0_7_FixNiveauOeuvres(),
      new _13_0_21_AjoutAppreciation(),
      new _13_0_22_PoidsDesMonnaies(),
      new _13_0_23_OmbreCategorieFalse(),
    ];
  }

  constructor() {
    game.settings.register(SYSTEM_RDD, "systemMigrationVersion", {
      name: "System Migration Version",
      scope: "world",
      config: false,
      type: String,
      default: "0.0.0",
    });
  }

  async migrate() {
    let currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion")
    if (currentVersion.startsWith("v")) {
      currentVersion = currentVersion.substring(1)
    }
    if (foundry.utils.isNewerVersion(game.system.version, currentVersion)) {
      // if (true) { /* comment previous and uncomment here to test before upgrade  */
      const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion)
        /* uncomment and set the version to migrate to to force a migration */
        // ||m.version == "13.0.21"
      )
      if (migrations.length > 0) {
        migrations.sort((a, b) => this.compareVersions(a, b));
        for (const m of migrations) {
          ui.notifications.info(
            `${LOG_HEAD} Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}`
          );
          await m.migrate();
        }
        ui.notifications.info(
          `Migrations done, version will change to ${game.system.version}`
        );
      } else {
        console.log(`${LOG_HEAD} No migration needeed, version will change to ${game.system.version}`
        );
      }

      game.settings.set(
        SYSTEM_RDD,
        "systemMigrationVersion",
        game.system.version
      );
    } else {
      console.log(`${LOG_HEAD} No system version changed`);
    }
  }

  compareVersions(a, b) {
    return foundry.utils.isNewerVersion(a.version, b.version) ? 1 : foundry.utils.isNewerVersion(b.version, a.version) ? -1 : 0;
  }
}
