/************************************************************************************/
// Some internal test strings
let str1 = `JABBERSLYTHE
M WS BS  S  T  I  Agi Dex
 Int WP Fel W
7  45 40 55   
50 20 35  -  10 20  - 20
Traits: Armour 3, Bestial, Bite+9, Bounce, Corrosive
Blood, Distracting, Infected, Maddening Aura (see
page 17), Night Vision, Size (Enormous), Tail +8,
Tongue Attack +5 (12), Venom, Weapon +9.
`;
let str = `REINER AND DIETER LEDERMANN
SMUGGLERS (BRASS 3)
M WS BS S
 T
 I
 Agi Dex Int WP Fel W
4
 33 33 32 35 38 41 39 33 37 38 12
Traits: Weapon (Dagger +5, Sword +7)
Skills: Bribery 43, Charm 43, Cool 42,
Consume Alcohol 45, Gossip 43, Haggle 43,
Lore (Local 38), Perception 43,
Secret Signs (Smuggler) 37
Talents: Briber, Criminal, Dealmaker,
Etiquette (Criminals, Doktor, Guilder)
Trappings: Dagger, Hand Weapon (Sword)
`

/************************************************************************************/
import "./xregexp-all.js";
const us_carac = 'm\\s+ws\\s+bs\\s+s\\s+t\\s+i\\s+agi?\\s+dex\\s+int\\s+\\wp\\s+fel\\s+w';
const fr_carac = 'm\\s+ws\\s+bs\\s+s\\s+t\\s+i\\s+agi?\\s+dex\\s+int\\s+\\wp\\s+fel\\s+w';
const carac_val = '(?<m>[0-9-]+)\\s+(?<ws>[0-9-]+)\\s+(?<bs>[0-9-]+)\\s+(?<s>[0-9-]+)\\s+(?<t>[0-9-]+)\\s+(?<i>[0-9-]+)\\s+(?<ag>[0-9-]+)\\s+(?<dex>[0-9-]+)\\s+(?<int>[0-9-]+)\\s+(?<wp>[0-9-]+)\\s+(?<fel>[0-9-]+)\\s+(?<w>[0-9-\*]+)';
const name_val = '(?<name>[a-zA-Z\\s\\-,]*)[\\s\\r\\na-zA-Z]*(?<tiers>.*|[\\(\\)a-z0-9]+)';
let sectionData = [
    { name: "trait", toFind:"Traits\\s*:", secondParse: '(?<name>[a-z\\s]*)[\\s\\+]*(?<value>.*|[0-9]+)', index:-1 },
    { name: "skill", toFind:"Skills\\s*:", secondParse: '(?<name>[a-z\\s\\(\\)]*)[\\s\\+]*(?<value>.*|[0-9]+)', index:-1 },
    { name: "talent", toFind:"Talents\\s*:", secondParse: '(?<name>[a-z\\-\\s!/]*)[\\s\\+]*(?<value>.*|[0-9]+)', index:-1 }, 
    { name: "trapping", toFind:"Trappings\\s*:", secondParse: '(?<name>[a-z\\s]*)[\\s\\+]*(?<value>.*|[0-9]+)', index:-1 }
  ];
let regSep = XRegExp('\\s*,\\s*', 'gi'); // Term separator, with auto trim
let regLine1 = XRegExp('[\\r\\n\\.]', 'gi'); // Term separator, with auto trim
let regName = XRegExp(name_val, 'gi');

/************************************************************************************/
async function __findItem(itemName, itemType, location = null) {
  itemName = itemName.trim();
  let items = game.items.entities.filter(i => i.type == itemType)

  // Search imported items first
  for (let i of items) {
    if (i.name == itemName && i.type == itemType)
      return i;
  }
  let itemList

  // find pack -> search pack -> return entity
  if (location) {
    let pack = game.packs.find(p => {
      location.split(".")[0] == p.metadata.package &&
        location.split(".")[1] == p.metadata.name
    })
    if (pack) {
      if (pack.translations[itemName])  {
        let translItemName = pack.translations[itemName].name;
        await pack.getIndex().then(index => itemList = index);
        let searchResult = itemList.find(t => t.name == translItemName)
        if (searchResult)
          return await pack.getEntity(searchResult._id)
      }
    }
  }

  // If all else fails, search each pack
  for (let p of game.packs.filter(p => p.metadata.tags && p.metadata.tags.includes(itemType))) {
    if (p.translations[itemName])  {
      let translItemName = p.translations[itemName].name;
      await p.getIndex().then(index => itemList = index);
      let searchResult = itemList.find(t => t.name == translItemName)
      if (searchResult)
        return await p.getEntity(searchResult._id)
    }
  }
}

/************************************************************************************/
async function __findSkill(skillName) {
  skillName = skillName.trim();
  // First try world items
  let worldItem = game.items.entities.filter(i => i.type == "skill" && i.name == skillName)[0];
  if (worldItem) return worldItem

  let skillList = [];
  let packs = game.packs.filter(p => p.metadata.tags && p.metadata.tags.includes("skill"))
  for (let pack of packs) {
    //console.log("SEARCH : ", skillName, pack);
    if ( pack.translations[skillName] ) {
      let translSkillName = pack.translations[skillName].name;
      skillList = await pack.getIndex()
      // Search for specific skill (won't find unlisted specializations)
      let searchResult = skillList.find(s => s.name == translSkillName)
      if (!searchResult)
        searchResult = skillList.find(s => s.name.split("(")[0].trim() == skillName.split("(")[0].trim())
      if (searchResult) {
        let dbSkill;
        await pack.getEntity(searchResult._id).then(packSkill => dbSkill = packSkill);
        dbSkill.data.name = translSkillName; // This is important if a specialized skill wasn't found. Without it, <Skill ()> would be added instead of <Skill (Specialization)>
        return dbSkill;
      }
    }
  }
  throw "Could not find skill (or specialization of) " + skillName + " in compendum or world"
}

/************************************************************************************/
async function __findTalent(talentName) {
  talentName = talentName.trim();
  // First try world items
  let worldItem = game.items.entities.filter(i => i.type == "talent" && i.name == talentName)[0];
  if (worldItem) return worldItem

  let talentList = [];
  let packs = game.packs.filter(p => p.metadata.tags && p.metadata.tags.includes("talent"))
  for (let pack of packs) {
    if ( pack.translations[talentName] ) {
      let translTalentName = pack.translations[talentName].name;
      talentList = await pack.getIndex()
      // Search for specific talent (won't find unlisted specializations)
      let searchResult = talentList.find(t => t.name == translTalentName)
      if (!searchResult)
        searchResult = talentList.find(t => t.name.split("(")[0].trim() == talentName.split("(")[0].trim())

      if (searchResult) {
        let dbTalent;
        await pack.getEntity(searchResult._id).then(packTalent => dbTalent = packTalent);
        dbTalent.data.name = translTalentName; // This is important if a specialized talent wasn't found. Without it, <Talent ()> would be added instead of <Talent (Specialization)>
        return dbTalent;
      }
    }
  }
  throw "Could not find talent (or specialization of) " + talentName + " in compendium or world"
}

/************************************************************************************/
export default async function statParserFR( statString, type = "npc") {
  let model = duplicate(game.system.model.Actor[type]);

  let reg1 = XRegExp(us_carac, 'gi');
  let res = reg1.test(statString);
  if (res) { //stat block identified go on
    // Extract the name
    let res1 = XRegExp.exec(statString, reg1);
    console.log("REG", res1);
    let pnjStr = statString.substring(0, res1.index);
    let nameRes = XRegExp.exec(pnjStr, regName );
    console.log(nameRes);
    if ( nameRes.tiers && nameRes.tiers.length > 0 && hasProperty(model, "details.status.value") )  {
      let regTiers = XRegExp("(?<name>[A-Za-z]*)\\s+(?<level>[0-9]*)");
      let resTiers = XRegExp.exec(nameRes.tiers, regTiers);
      console.log(resTiers);
      model.details.status.value = game.i18n.localize(resTiers.name.trim()) + " " +  resTiers.level;
    }
    // Compute the PNJ name
    let pnjName = nameRes.name.split("—")[0].split(" ").filter(f => !!f);
    pnjName = pnjName.map(word => {
        if (word == "VON")
            return word.toLowerCase();

        word = word.toLowerCase();
        word = word[0].toUpperCase() + word.substring(1, word.length);
        return word;
    })
    pnjName = pnjName.join(" ")

    // Get the carac values
    let reg2 = XRegExp(carac_val, 'gi');
    let resCarac = XRegExp.exec(statString, reg2); // resr contains all carac found
    
    // Setup carac
    if (resCarac["Agi"]) resCarac["Ag"] = resCarac["Agi"]; // Auto patch
    model.details.move.value = Number(resCarac["m"]);
    for (let key in model.characteristics) {
      if (resCarac[key] === '-') resCarac[key] = 0;
      model.characteristics[key].initial = Number(resCarac[key]);
    }
    //console.log("CARAC", model.characteristics);

    // Search position of skills/talents/...
    for( let def of sectionData ) {
      def.regDef = XRegExp(def.toFind, 'gi');
      let res = XRegExp.exec(statString, def.regDef);
      if (res ) def.index = res.index; // Get the index in the string
      //console.log("   Parsing", def.name, res);
    }
    // Sort to split position of various substring
    sectionData.sort( function(a, b) { return a.index - b.index; } );
    
    let globalItemList = [];
    // Then loop again and process each item type
    for(let i=0; i< sectionData.length; i++ ) {
      let def = sectionData[i];
      if ( def.index > -1) {
        let maxIndex = statString.length;
        if ( sectionData[i+1] && sectionData[i+1].index > -1 )
          maxIndex = sectionData[i+1].index;
        def.substring = statString.substring(def.index, maxIndex);
        def.substring = XRegExp.replace(def.substring, def.regDef, "");
        def.substring = XRegExp.replace(def.substring, regLine1, " ");
        // At this point, def.substring contains the items list as a string
        
        // Then create a table of it in termList, with specific sub-parsing rules
        let termList = XRegExp.split(def.substring, regSep);
        for (let name of termList) {
          let itemFound, subres;          
          if (def.secondParse) { 
            subres = XRegExp.exec( name, XRegExp(def.secondParse, 'gi') );
            name = subres.name.trim();
          }
          if ( def.name == 'trait') {
            try { 
              itemFound = await __findItem(name, "trait");
            }
            catch {}
            if ( itemFound && subres && subres.value.length > 0 ) {
              subres.value = XRegExp.replace(subres.value, "(", "");
              subres.value = XRegExp.replace(subres.value, ")", "");
              itemFound.data.data.specification.value = game.i18n.localize( subres.value);
            }
            if (!itemFound)
              ui.notifications.error("Trait non trouvé, à ajouter manuellemen : " + name, { permanent: true })
          } else if  ( def.name == 'skill') {
            try {
              itemFound = await __findSkill(name);
            }
            catch {}
            if ( itemFound && subres && subres.value) {
              itemFound.data.data.advances.value = Number(subres.value) - Number(resCarac[itemFound.data.data.characteristic.value]);
            }
            if (!itemFound)
              ui.notifications.error("Compétence non trouvée, à ajouter manuellement : " + name, { permanent: true })
          } else if (def.name == 'talent') {
            try {
              itemFound = await __findTalent(name);
            }
            catch {}
            if ( itemFound && subres && subres.value)
              itemFound.data.data.advances.value = Number(subres.value);
            if (!itemFound)
              ui.notifications.error("Talent non trouvé, à ajouter manuellement : " + name, { permanent: true })
          } else if (def.name == 'trapping') {
            try {
              itemFound = await __findItem(name, "trapping");
            }
            catch {}
            if (!itemFound) {
              itemFound = new game.wfrp4e.entities.ItemWfrp4e({ img: "systems/wfrp4e/icons/blank.png", name: name, type: "trapping", data: game.system.model.Item.trapping })
              itemFound.data.data.trappingType.value = "misc"
            } 
          }
          if (itemFound)
            globalItemList.push( itemFound );
        }
      }
    }
    let moneyItems = await game.wfrp4e.utility.allMoneyItems() || [];
    moneyItems = moneyItems.sort((a, b) => (a.data.coinValue.value > b.data.coinValue.value) ? -1 : 1);
    moneyItems.forEach(m => m.data.quantity.value = 0)
    globalItemList = globalItemList.concat(moneyItems);
    //console.log("My liste :", globalItemList);
    let name = pnjName;
    return { name, type, data: model, items: globalItemList }
  }

  // If the carac string has not been found
  ui.notifications.error("Impossible de convertir ces statitiques, les caractéristiques n'ont pas été trouvées", { permanent: true } )
}

/************************************************************************************/
Hooks.once('ready', () => {
  
  //var fullskills  = game.packs.get('wfrp4e-core.skills');        
  //console.log("Skills", game.wfrp4e.apps.StatBlockParser.prototype);

} )

