import { Grammar } from "./grammar.js";

const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]];

const competence_xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
const competence_niveau_max = competence_xp_par_niveau.length - 10;
/* -------------------------------------------- */
const limitesArchetypes = [
  { "niveau": 0, "nombreMax": 100, "nombre": 0 },
  { "niveau": 1, "nombreMax": 10, "nombre": 0 },
  { "niveau": 2, "nombreMax": 9, "nombre": 0 },
  { "niveau": 3, "nombreMax": 8, "nombre": 0 },
  { "niveau": 4, "nombreMax": 7, "nombre": 0 },
  { "niveau": 5, "nombreMax": 6, "nombre": 0 },
  { "niveau": 6, "nombreMax": 5, "nombre": 0 },
  { "niveau": 7, "nombreMax": 4, "nombre": 0 },
  { "niveau": 8, "nombreMax": 3, "nombre": 0 },
  { "niveau": 9, "nombreMax": 2, "nombre": 0 },
  { "niveau": 10, "nombreMax": 1, "nombre": 0 },
  { "niveau": 11, "nombreMax": 1, "nombre": 0 }
];

/* -------------------------------------------- */
const categorieCompetences = {
  "generale": { level: "-4", label: "Générales" },
  "particuliere": { level: "-8", label: "Particulières" },
  "specialisee": { level: "-11", label: "Spécialisées" },
  "connaissance": { level: "-11", label: "Connaissances" },
  "draconic": { level: "-11", label: "Draconics" },
  "melee": { level: "-6", label: "Mêlée" },
  "tir": { level: "-8", label: "Tir" },
  "lancer": { level: "-8", label: "Lancer" }
}

const compendiumCompetences = {
  "personnage": "foundryvtt-reve-de-dragon.competences",
  "creature": "foundryvtt-reve-de-dragon.competences-creatures",
  "entite": "foundryvtt-reve-de-dragon.competences-entites"
};


function _buildCumulXP() {
  let cumulXP = { "-11": 0 };
  let cumul = 0;
  for (let i = 0; i <= competence_xp_par_niveau.length; i++) {
    let level = i - 10;
    cumul += competence_xp_par_niveau[i];
    cumulXP[level] = cumul;
  }
  return cumulXP;
}

const competence_xp_cumul = _buildCumulXP();

export class RdDItemCompetence extends Item {

  static actorCompendium(actorType) {
    return compendiumCompetences[actorType];
  }

  static getCategorieCompetences() {
    return categorieCompetences;
  }
  static getNiveauBase(category) {
    return categorieCompetences[category].level;
  }
  static getLabelCategorie(category) {
    return categorieCompetences[category].label;
  }

  static getEsquive(competences) {
    return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 };
  }

  /* -------------------------------------------- */
  static isCompetenceArme(competence) {
    switch (competence.data.categorie) {
      case 'melee':
        return competence.name != 'Esquive';
      case 'tir':
      case 'lancer':
        return true;
    }
    return false;
  }

  /* -------------------------------------------- */
  static isArmeUneMain(competence) {
    return competence?.name.toLowerCase().includes("1 main");
  }
  static isArme2Main(competence) {
    return competence?.name.toLowerCase().includes("2 main");
  }

  /* -------------------------------------------- */
  static isMalusEncombrementTotal(competence) {
    return competence?.name.toLowerCase().match(/(natation|acrobatie)/);
  }

  /* -------------------------------------------- */
  static isTronc(compName) {
    for (let troncList of competenceTroncs) {
      for (let troncName of troncList) {
        if (troncName == compName)
          return troncList;
      }
    }
    return false;
  }

  /* -------------------------------------------- */
  static computeTotalXP(competences) {
    const total = competences.map(c => RdDItemCompetence.computeXP(c))
      .reduce((a, b) => a + b, 0);
    const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences);
    return total - economieTronc;
  }

  /* -------------------------------------------- */
  static computeXP(competence) {
    const factor = competence.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
    const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.data.base, competence.data.niveau ?? competence.data.base);
    const xp = competence.data.xp ?? 0;
    const xpSort = competence.data.xp_sort ?? 0;
    return factor * (xpNiveau + xp) + xpSort;
  }

  /* -------------------------------------------- */
  static computeEconomieXPTronc(competences) {
    return competenceTroncs.map(
      list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
        // calcul du coût xp jusqu'au niveau 0 maximum
        .map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0)))
        .sort((a, b) => b - a) // tri descendant
        .splice(0, 1) // ignorer le coût xp le plus élevé
        .reduce((a, b) => a + b, 0)
    ).reduce((a, b) => a + b, 0);
  }

  /* -------------------------------------------- */
  static computeDeltaXP(from, to) {
    RdDItemCompetence._valideNiveau(from);
    RdDItemCompetence._valideNiveau(to);
    return competence_xp_cumul[to] - competence_xp_cumul[from];
  }


  /* -------------------------------------------- */
  static computeCompetenceXPCost(competence) {
    let xp = RdDItemCompetence.getDeltaXp(competence.data.base, competence.data.niveau ?? competence.data.base);
    xp += competence.data.xp ?? 0;
    if (competence.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
    xp += competence.data.xp_sort ?? 0;
    return xp;
  }

  /* -------------------------------------------- */
  static computeEconomieCompetenceTroncXP(competences) {
    let economie = 0;
    for (let troncList of competenceTroncs) {
      let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
        .sort((c1, c2) => c2.data.niveau - c1.data.niveau); // tri du plus haut au plus bas
      list.splice(0, 1); // ignorer la plus élevée
      list.forEach(c => {
        economie += RdDItemCompetence.getDeltaXp(c.data.base, Math.min(c.data.niveau, 0));
      });
    }
    return economie;
  }

  static levelUp(itemData) {
    itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
    itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext;
  }

  static isVisible(itemData) {
    return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
  }

  /* -------------------------------------------- */
  static isNiveauBase(itemData) {
    return Number(itemData.data.niveau) == RdDItemCompetence.getNiveauBase(itemData.data.categorie);
  }

  /* -------------------------------------------- */
  static findCompetence(list, name) {
    name =  Grammar.toLowerCaseNoAccent(name);
    const competences = list.filter(it => Grammar.toLowerCaseNoAccent(it.name).includes(name) && (it.type == "competence" || it.type == "competencecreature"));
    if (competences.length == 0) {
      return undefined;
    }
    const competence = competences[0];
    if (competences.length>1) {
      const names = competences.map(it => it.name).reduce((a, b) => `${a}<br>${b}`);
      ui.notifications.info(`Plusieurs compétences possibles:<br>${names}<br>La première sera choisie: ${competence.name}`);
    }
    return competence;
  }

  /* -------------------------------------------- */
  static getCompetenceNextXp(niveau) {
    return RdDItemCompetence.getCompetenceXp(niveau + 1);
  }

  /* -------------------------------------------- */
  static getCompetenceXp(niveau) {
    RdDItemCompetence._valideNiveau(niveau);
    return niveau < -10 ? 0 : competence_xp_par_niveau[niveau + 10];
  }

  /* -------------------------------------------- */
  static getDeltaXp(from, to) {
    RdDItemCompetence._valideNiveau(from);
    RdDItemCompetence._valideNiveau(to);
    return competence_xp_cumul[to] - competence_xp_cumul[from];
  }

  /* -------------------------------------------- */
  static _valideNiveau(niveau) {
    if (niveau < -11 || niveau > competence_niveau_max) {
      console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${competence_niveau_max} ]`);
    }
  }

  /* -------------------------------------------- */
  static computeResumeArchetype(competences) {
    const archetype = RdDItemCompetence.getLimitesArchetypes();
    competences.forEach(it => {
      let niveau = Math.max(0, it.data.niveau_archetype);
      archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
      archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
    });
    return archetype;
  }

  /* -------------------------------------------- */
  static getLimitesArchetypes() {
    return duplicate(limitesArchetypes);
  }

}