/**
 * Creates tabs for a sheet object
 */
 export const createTabs = function(html, tabGroups) {
    // Create recursive activation/callback function
    const _recursiveActivate = function(rtabs, tabName=null) {
      if (tabName == null) this._initialTab[rtabs.group] = rtabs.active;
      else {
        rtabs.activate(tabName);
        this._initialTab[rtabs.group] = tabName;
      }
  
      // Scroll to previous position
      let scrollElems = html.find(`.scroll-${rtabs.group}`);
      if (scrollElems.length === 0) scrollElems = html.find(`.tab[data-group="${rtabs.group}"]`);
      for (let o of scrollElems) { o.scrollTop = this._scrollTab[rtabs.group]; }
  
      // Recursively activate tabs
      for (let subTab of rtabs.subTabs) {
        _recursiveActivate.call(this, subTab, subTab.active);
      }
    };
  
    // Create all tabs
    const _func = function(group, children) {
      if (html.find(`nav[data-group="${group}"]`).length === 0) return null;
  
      if (this._initialTab == null) this._initialTab = {};
      if (this._scrollTab == null) this._scrollTab = {};
  
      const subHtml = html.find(`.${group}-body > div[data-group="${group}"]`);
      const activeSubHtml = subHtml.filter(".active");
      const initial = this._initialTab[group] !== undefined ? this._initialTab[group] : (activeSubHtml.length > 0 ? activeSubHtml[0].dataset.tab : "");
  
      // Set up data for scroll position and active tab
      if (this._scrollTab[group] === undefined) this._scrollTab[group] = 0;
      if (this._initialTab[group] === undefined) this._initialTab[group] = initial;
  
      // Set up scrolling callback
      let scrollElems = html.find(`.scroll-${group}`);
      if (scrollElems.length === 0) scrollElems = html.find(`.tab[data-group="${group}"]`);
      scrollElems.scroll(ev => this._scrollTab[group] = ev.currentTarget.scrollTop);
  
      // Create tabs object
      const tabs = new TabsV2({
        navSelector: `.tabs[data-group="${group}"]`,
        contentSelector: `.${group}-body`,
        callback: (_, tabs) => {
          _recursiveActivate.call(this, tabs);
        },
      });
  
      // Recursively create tabs
      tabs.group = group;
      tabs.subTabs = [];
      for (let [childKey, subChildren] of Object.entries(children)) {
        const newTabs = _func.call(this, childKey, subChildren);
        if (newTabs != null) tabs.subTabs.push(newTabs);
      }
  
      tabs.bind(html[0]);
      _recursiveActivate.call(this, tabs, this._initialTab[group]);
      return tabs;
    };
  
    for (const groupKey of Object.keys(tabGroups)) {
      _func.call(this, groupKey, tabGroups[groupKey]);
    }
  };


  export function wasImportedBefore() {
    for (let folder of game.folders) {
      if (folder.name.startsWith(`DMDave - Chain Devil Crypts`))
        return true;
    }
    return false;
  }


export async function importData() {
  function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&amp;")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;"); 
 }

 function unicodeEscape(str) {
  return str.replace(/[A-zÀ-ÖØ-öø-įĴ-őŔ-žǍ-ǰǴ-ǵǸ-țȞ-ȟȤ-ȳɃɆ-ɏḀ-ẞƀ-ƓƗ-ƚƝ-ơƤ-ƥƫ-ưƲ-ƶẠ-ỿ]/g, function(character) {
    var escape = character.charCodeAt().toString(16),
        longhand = escape.length > 2;
    return '\\' + (longhand ? 'u' : 'x') + ('0000' + escape).slice(longhand ? -4 : -2);
  });
}
  
  console.log('DRGH | Starting import')
  const module = game.modules.get("dmdave-chain-devil-crypts");
  const moduleName = "dmdave-chain-devil-crypts"
  let scenes = null;
  let actors = [];
  let items = [];

  for (let folder of game.folders) {
    if (folder.name.startsWith(`DMDave - Chain Devil Crypts`))
      await folder.update({name: '(Old) ' + folder.name})
  }

  let journalNameToId = new Map()
  let journalNewNameToId = new Map()
  let folderTreeMap = new Map()

  // Create folders for Journals
  let baseFolder = await Folder.create({name: `DMDave - Chain Devil Crypts`, type: 'JournalEntry', parent: null});
  let adventureFolder = null; 
  let npcFolder = null; 
  let handoutsFolder = null; 

  let importedJournals = new Set();

  for ( let p of module.packs ) {
          if (p.system !== game.system.id && p.system) continue;
          const pack = game.packs.get("dmdave-chain-devil-crypts."+p.name);
          if ( (p.entity || p.type) !== "Playlist" && (p.entity || p.type) !== "JournalEntry" ) await pack.importAll();
          else if ((p.entity || p.type) === "Playlist") {
                  const music = await pack.getDocuments();
                  Playlist.create(music.map(p => p.data));
          } else {
            const journals = await pack.getDocuments();
            for (let element of journals) {
              let importedElement = await game.journal.importFromCompendium(pack,element.id);
              journalNameToId.set(importedElement.name, importedElement.id)
              if (element.name.startsWith('NPC - ')) {
                if (npcFolder === null) npcFolder = await Folder.create({name: 'Characters', type: 'JournalEntry', parent: baseFolder, sorting: "m"});
                await importedElement.update({folder:npcFolder.id, name:importedElement.name.replace('NPC - ','')})
              }
              else if (element.name.startsWith('Handout - ')) {
                if (handoutsFolder === null) handoutsFolder = await Folder.create({name: 'Handouts', type: 'JournalEntry', parent: baseFolder, sorting: "m"});
                await importedElement.update({folder:handoutsFolder.id, name:importedElement.name.replace('Handout - ','')})
              }
              else {
                let customFolder = null;
                let importedName = null;
                console.log('DRGH | Importing Journal', importedElement.name);
                if (importedElement.name.indexOf(">") === -1) {
                  if (adventureFolder === null) {
                    console.log('DRGH | Creating adventure folder', importedElement.name);
                    adventureFolder = await Folder.create({name: 'Adventure', type: 'JournalEntry', parent: baseFolder, sorting: "m"});
                  }
                  customFolder = adventureFolder;
                  importedName = importedElement.name;
                } else {
                  let folderTree = importedElement.name.split(">");
                  console.log('DRGH | Folder Tree', folderTree);
                  importedName = folderTree.pop().trim();
                  let treeFolder = baseFolder;
                  while (folderTree.length) {
                    let baseFolderName = folderTree.shift().trim();
                    console.log('DRGH | Folder Name', baseFolderName);
                    let folderSortId = parseInt(baseFolderName)
                    if (!folderTreeMap.has(baseFolderName)) {
                      console.log('DRGH | Parent Name', treeFolder);
                      treeFolder = await Folder.create({name: baseFolderName.replace(`${folderSortId}. `,''), type: 'JournalEntry', parent: treeFolder, sorting: "m", sort: folderSortId});
                      folderTreeMap.set(baseFolderName, treeFolder);
                    } else {
                      treeFolder = folderTreeMap.get(baseFolderName)
                    }
                  }
                  customFolder = treeFolder;
                }
                var sortId = parseInt(importedName)
  
                console.log('DRGH | Importing Journal', sortId, importedName);
                await importedElement.update({folder:customFolder.id, name:importedName.replace(`${sortId}. `,''), sort: sortId})
              }
              journalNewNameToId.set(importedElement.id, importedElement.name)
              importedJournals.add(importedElement)
            }
          }

          if ( p.entity === "Scene" || p.type === "Scene" ) scenes = game.folders.getName(p.label);
          if ( p.entity === "Actor" || p.type === "Actor"  ) actors.push(game.folders.getName(p.label));
          if ( p.entity === "Item" || p.type === "Item"  ) items.push(game.folders.getName(p.label));
  }

  for (let journal of importedJournals) {
    let journalContent = journal.data.content;
    if (journalContent) {
      journalContent = journalContent.replace(new RegExp(`<p`,"gi"), `<p class="${moduleName}"`)
      journalContent = journalContent.replace(new RegExp(`<section>`,"gi"), `<section class="${moduleName}">`)
      journalContent = journalContent.replace(new RegExp(`<blockquote>`,"gi"), `<blockquote class="${moduleName} read">`)
      journalContent = journalContent.replace(new RegExp(`<blockquote class="hard">`,"gi"), `<blockquote class="${moduleName} hard">`)
      journalContent = journalContent.replace(new RegExp(`<section class="secret">`,"gi"), `<section class="secret ${moduleName}">`)
      journalContent = journalContent.replace(new RegExp(`<h1`,"gi"), `<h1 class="${moduleName}"`)
      journalContent = journalContent.replace(new RegExp(`<h2`,"gi"), `<h2 class="${moduleName}"`)
      journalContent = journalContent.replace(new RegExp(`<h3`,"gi"), `<h3 class="${moduleName}"`)
      journalContent = journalContent.replace(new RegExp(`<h4`,"gi"), `<h4 class="${moduleName}"`)
      journalContent = journalContent.replace(new RegExp(`<li`,"gi"), `<li class="${moduleName}"`)
    }
    // Actors mapping
    actors.forEach(_directory => {
      _directory.contents.forEach(_actor => {
        if (journalContent) {
          journalContent = journalContent.replace(new RegExp(`\\\{${escapeHtml(unicodeEscape(_actor.name))}\\\}`,"gi"), `<b>@Actor[${escapeHtml(_actor.id)}]{${escapeHtml(_actor.name)}}</b>`)
          let name = escapeHtml(unicodeEscape(_actor.name));
          journalContent = journalContent.replace(new RegExp(`\\\{([^\\\{]+?)\\\|${name}\\\}`,"gi"), `<b>@Actor[${escapeHtml(_actor.id)}]{$1}</b>`)
        }
          
      })
    })
    // Item mapping
    items.forEach(_directory => {
      _directory.contents.forEach(_item => {
        if (journalContent) {
          journalContent = journalContent.replace(new RegExp(`\\\|${escapeHtml(unicodeEscape(_item.name))}\\\|`,"gi"), `<em>@Item[${escapeHtml(_item.id)}]{${escapeHtml(_item.name)}}</em>`)
        }
          
      })
    })
    // Jounral linking
    importedJournals.forEach(_journal => {
      if (journal !== _journal && journalContent) {
        journalContent = journalContent.replace(new RegExp(`\\\[${escapeHtml(unicodeEscape(_journal.name))}\\\]`,"gi"), `@JournalEntry[${escapeHtml(_journal.id)}]{${escapeHtml(_journal.name)}}`)
        let name = escapeHtml(unicodeEscape(_journal.name));
        journalContent = journalContent.replace(new RegExp(`\\\[([^\\\[]+?)\\\|${name}\\\]`,"gi"), `@JournalEntry[${escapeHtml(_journal.id)}]{$1}`)
      }
    })
    
    if (journalContent)
      await journal.update({'content':journalContent})
  }

  // Re-associate Tokens for all scenes
  const sceneUpdates = [];
  for ( let s of scenes.contents ) {
          const tokens = duplicate(s.data.tokens).map(t => {
                  for (let actorsDirectory of actors) {
                      const a = actorsDirectory.contents.find(a => a.data?.token?.name === t.name);
                      if (a) {

                              t.actorId = a ? a.id : null;
                              t.actorLink = a ? a.data?.token?.actorLink || false : false;
                              if (a.data?.data?.traits?.size === 'lg') {
                                      t.height = 2;
                                      t.width = 2;
                              } else if (a.data?.data?.traits?.size === 'huge') {
                                      t.height = 3;
                                      t.width = 3;
                              } else if (a.data?.data?.traits?.size === 'med') {
                                      t.height = 1;
                                      t.width = 1;
                              } 
                              console.log('DRGH | Linking actor', a)
                      }
                  }
                  return t;
          });
          let notes = duplicate(s.data.notes).map(t => {
            journalNameToId.forEach((v, k) => {
              console.log('DRGH | Looking for journal', k, v, t)
              if (t.text === k) {
                t.entryId = v;
                t.text = journalNewNameToId.get(v)
                console.log('DRGH | Linking journal', t, v)
              }
            })
            return t
          });
          sceneUpdates.push({_id: s.id, tokens, notes});
  }
  console.log('DRGH | Linking actors and journals', sceneUpdates)
  await Scene.updateDocuments(sceneUpdates);


  // Display the introduction
  const j1 = game.journal.getName("Chain Devil Crypts");
  if ( j1 ) j1.sheet.render(true, {sheetMode: "text"});
}
