/************************************************************************************/
import "./xregexp-all.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDBaseActorReve } from "../actor/base-actor-reve.js";

/************************************************************************************/
// Some internal test strings
let statBlock01 = `+$16(/, baron de Sylvedire, né à l’heure du
Roseau, 40 ans, 1m78, 65 kg, Beauté 13.
TAILLE
 10
 Mêlée
 14
APPARENCE
 13
 Tir
 11
CONSTITUTION
 12
 Lancer
 11
FORCE
 12
 Dérobée
 13
AGILITÉ
 16
 Vie
 11
DEXTÉRITÉ
 13
 Endurance
 25
VUE
 10
 +dom
 0
OUÏE
 11
 Protection
 2 ou 4
ODO-GOÛT
 9
 cuir souple
VOLONTÉ
 14
 ou cuir / métal
INTELLECT
 9
EMPATHIE
 11
RÊVE
 13
CHANCE
 10
niv
 init
 +dom
Épée dragonne
 +5
 12
 +3
Hache de bataille
 +6
 13
 +3
Bouclier moyen
 +5
Dague mêlée
 +4
 11
 +1
Corps à corps
 +4
 11
 (0)
Esquive
 +8
Escalade +4 / Saut +5 / Commerce +3 / Équitation
+6 / Chirurgie 0 / Survie en extérieur +4 / Survie fo-
rêt +6 / Acrobatie -2 / Métallurgie +2 / Natation +3 /
Légendes -1 / Écriture -4 
`;

let statBlock02 = `/HVJDUGHV
TAILLE
 11
 Mêlée
 12
CONSTITUTION
 11
 Tir
 11
FORCE
 12
 Lancer
 11
AGILITÉ
 12
 Dérobée
 11
DEXTERITÉ
 11
 Vie
 11
VUE
 11
 Endurance
 22
OUÏE
 11
 Vitesse
 12
VOLONTÉ
 10
 +dom
 0
Protection
 4
cuir / métal
niv
 init
 +dom
Hache de bataille
 +4
 10
 +3
Bouclier moyen
 +4
Dague mêlée
 +3
 9
 +1
Arc
 +5
 10
 +2
Corps à corps
 +3
 9
 (0)
Esquive avec armure
 +2
Course +1/ Vigilance +4
`;

let statBlock03 = `rencontres sont laissées à /HVFKLHQVORXSVGXEDURQ
 chaque gardien des rêves.
TAILLE
 8
 Vie
 10
CONSTITUTION FORCE
 12
 11
 Endurance
 Vitesse
 12/38
 21
 /HVFKLHQV]RPELV
PERCEPTION 13
 +dom
 0
VOLONTÉ
 10
 Protection
 0
 Les « monstres » apparaîtront un soir, durant
RÊVE
 10
 l’heure du Serpent, et attaqueront les voya-
niv
 init
 +dom
 geurs à leur campement. Si ces derniers ne
Morsure
 13
 +4
 10
 +1
 campent pas, ils apparaîtront tout de même à
Esquive
 11
 +3
 l’heure du Serpent. Le feu ne les effraie pas. Ils
Course, Saut
 12
 +3
 ne sont pas très rapides, mais en revanche, très
Discrétion
 12
 +3
 silencieux : ils n’aboient pas. Les voyageurs
Vigilance
 13
 +3
 `
// Skill parser depending on the type of actor
const compParser = { personnage: "\\s+(?<value>[\\+\\-]?\\d+)", creature: "\\s+(?<carac>\\d+)\\s+(?<value>[\\+\\-]?\\d+)\\s?(?<init>\\d+)?\\s+?(?<dommages>\\+\\d+)?" };

// Main class for parsing a stat block
export class RdDStatBlockParser {
  
  static openInputDialog() {
    let dialog = new Dialog({
      title: "Import de stats de PNJ/Créatures",
      content: `
        <div>
          <p>Coller le texte de la stat ici</p>
          <textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
        </div>
      `,
      buttons: {
        ok: {
          label: "OK",
          callback: async (html) => {
            let statBlock = html.find("#statBlock")[0].value;
            await RdDStatBlockParser.parseStatBlock(statBlock);
            dialog.close();
          }
        },
        cancel: {
          label: "Cancel"
        }
      }
    });
    dialog.render(true);
  }
  
  static fixWeirdPDF(statString) {
    // Split the statString into lines
    let lines = statString.split("\n");
    let newLines = [];
    let index = 0;
    let nextType = "string";
    // Loop through each line
    for (let i = 0; i < lines.length; i++) {
      // remove trailing spaces
      lines[i] = lines[i].trim();
      // Is it text ?      
      if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
        if ( nextType == "string" ) { 
          newLines[index] = lines[i];
          nextType = "number";  
        } else {
          console.log("Wrong sequence string detected...", lines[i], nextType);
        }
      }
      // Is it a number ?
      if (lines[i].match(/^[\d\s]+/)) {
        if ( nextType == "number" ) {
          newLines[index] = newLines[index] + lines[i];
          nextType = "string";
          index++;
        } else {
          console.log("Wrong sequence number detected...", lines[i], nextType);
        }
      }
    }

  }  
  
  static async parseStatBlock(statString, type = "npc") {

    //statString = statBlock03;
    if (!statString) {
      return;
    }

    // Special function to fix strange/weird copy/paste from PDF readers
    // Unused up to now : this.fixWeirdPDF(statString);

    // Replace all endline by space in the statString
    statString = statString.replace(/\n/g, " ");
    // Remove all multiple spaces
    statString = statString.replace(/\s{2,}/g, " ");
    // Remove all leading and trailing spaces
    statString = statString.trim();

    let actorType = "personnage";
    let perception = XRegExp.exec(statString.toLowerCase(), XRegExp("perception\\s+(?<value>\\d+)", 'gi'));
    if (perception?.value ) { 
      actorType = "creature";
    }

    // Now start carac 
    let actorData = foundry.utils.deepClone(game.model.Actor[actorType]); 
    for (let key in game.model.Actor.personnage.carac) {
      let caracDef = game.model.Actor.personnage.carac[key];
      // Parse the stat string for each caracteristic
      let carac = XRegExp.exec(statString.toLowerCase(), XRegExp(caracDef.label.toLowerCase()+"\\s+(?<value>\\d+)", 'gi'));
      if (carac?.value) {
        actorData.carac[key].value = Number(carac.value);
      }
    }

    // If creature we need to setup additionnal fields 
    if (actorType == "creature") {
      let plusDom  = XRegExp.exec(statString.toLowerCase(), XRegExp("\\+dom\\s+(?<value>\\+\\d+)", 'gi'));
      if (plusDom?.values) {
        actorData.attributs.plusdom.value = Number(plusDom.value);
      }
      let protection  = XRegExp.exec(statString.toLowerCase(), XRegExp("protection\\s+(?<value>\\d+)", 'gi'));
      if (protection?.value) {
        actorData.attributs.protection.value = Number(protection.value);
      }
      let endurance = XRegExp.exec(statString.toLowerCase(), XRegExp("endurance\\s+(?<value>\\d+)", 'gi'));
      if (endurance?.value) {
        actorData.sante.endurance.value = Number(endurance.value);
        actorData.sante.endurance.max = Number(endurance.value);
      }
      let vie = XRegExp.exec(statString.toLowerCase(), XRegExp("vie\\s+(?<value>\\d+)", 'gi'));
      if (vie.value) {
        actorData.sante.vie.value = Number(vie.value);
        actorData.sante.vie.max = Number(vie.value);
      }
      let vitesse = XRegExp.exec(statString.toLowerCase(), XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'gi'));
      if (vitesse?.value) {
        actorData.attributs.vitesse.value = vitesse.value;
      }
    }

    let items = [];
    // Get skills from compendium 
    const competences = await SystemCompendiums.getCompetences(actorType);
    //console.log("Competences : ", competences);
    let allComp = competences.map(i => i.toObject())
    for (let comp of allComp) {
      let skill = XRegExp.exec(statString.toLowerCase(), XRegExp(comp.name.toLowerCase()+compParser[actorType], 'gi'));
      if (skill) {
        comp.system.niveau = Number(skill.value);
        if (actorType == "creature") {
          comp.system.carac_value = Number(skill.carac);
          if (skill.init) {
            comp.system.dommages = Number(skill.dommages);
            comp.system.iscombat = true;
          }
          items.push(comp); // Only selective push
        }
      }
      if (actorType == "personnage") {
        items.push(comp); // Always push
      }
    }

    // Now process weapons
    const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement")
    //console.log("Equipement : ", equipment);
    for (let w of weapons) {
      
      let weapon = XRegExp.exec(statString.toLowerCase(), XRegExp(w.name.toLowerCase()+"\\s+(?<value>\\+\\d+)", 'gi'));
      if (weapon) {
        w.system.equipe = true
        items.push(w.toObject());
        // now process the skill
        if ( w.system?.competence != "") {
          let wComp = items.find(i => i.name.toLowerCase() == w.system.competence.toLowerCase());  
          if (wComp) {
            wComp.system.niveau = Number(weapon.value);
          }
        }
        if ( w.system?.tir != "") {
          let wComp = items.find(i => i.name.toLowerCase() == w.system.tir.toLowerCase());  
          if (wComp) {
            wComp.system.niveau = Number(weapon.value);
          }
        }
        if ( w.system?.lancer != "") {
          let wComp = items.find(i => i.name.toLowerCase() == w.system.lancer.toLowerCase());  
          if (wComp) {
            wComp.system.niveau = Number(weapon.value);
          }
        }
      }
    }

    // Now process armors
    const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement")
    for (let a of armors) {    
      let armor = XRegExp.exec(statString.toLowerCase(), XRegExp(a.name.toLowerCase(), 'gi'));
      if (armor) {
        a.system.equipe = true
        items.push(a.toObject());
      }
    }

    // Get hour name : heure du XXXXX
    let heure = XRegExp.exec(statString.toLowerCase(), XRegExp("heure du\\s+(?<value>\\w+)", 'gi'));
    if (heure?.value) {
      actorData.heure = heure.value;  
    }
    // Get age
    let age = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) ans", 'gi'));
    if (age?.value) {
      actorData.age = Number(age.value);  
    }
    // Get height
    let taille = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+)m\\d+", 'gi'));
    if (taille?.value) {
      actorData.taille = taille.value;  
    }
    // Get weight
    let poids = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) kg", 'gi'));
    if (poids?.value) {
      actorData.poids = poids.value;  
    }
    // Get beauty
    let beaute = XRegExp.exec(statString.toLowerCase(), XRegExp("beauté\\s+(?<value>\\d+)", 'gi'));
    if (beaute?.value) {
      actorData.beaute = Number(beaute.value);  
    }

    // Name is all string before ', né'
    let name
    if (actorType == "personnage") {
      name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>[\\w\\s\\d]+),", 'gi'));
      if (!name?.value) {
        name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
      }
      name = name?.value || "Importé";
    }
    if (actorType == "creature") {
      name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
      name = name?.value || "Importé";
    }
    
    let newActor = RdDBaseActorReve.create({name: name || "Importé", type:actorType, system: actorData, items: items});

    // DUmp....
    console.log(actorData);
  }
}

