/**
 * Build the filetree
 * @param {HTMLElement} parent Root element of the filetree
 * @param {{name: string, is_dir: boolean, children: any[]}} data FileNode
 * @param {string} location Current location, used for links creation
 */
const buildFileTree = (parent, data, location) => {
  const fragment = document.createDocumentFragment();
  const ul = document.createElement("ul");
  fragment.appendChild(ul);

  data.forEach((item) => {
    const li = document.createElement("li");
    li.classList.add(item.is_dir ? "directory" : "file");

    if (item.is_dir) {
      // Directory
      li.textContent = item.name;
      li.classList.add("collapsed");

      // Toggle collapsing on click
      li.addEventListener(
        "click",
        (e) => {
          if (e.target === li) {
            li.classList.toggle("collapsed");
          }
        },
        { passive: true }
      );
    } else {
      // File
      const url = window.location.href.split("?")[0];
      const a = document.createElement("a");
      a.text = item.name;
      a.href = `${url}?q=${location}${item.name}`;
      li.appendChild(a);
    }

    ul.appendChild(li);

    if (item.children?.length) {
      buildFileTree(
        li,
        item.children,
        item.is_dir ? `${location}${item.name}/` : location
      );
    }
  });

  parent.appendChild(fragment);
};

/**
 * Uncollapse elements from the deepest element
 * @param {HTMLLIElement} element Element to uncollapse
 */
const uncollapse = (element) => {
  if (element) {
    element.classList.remove("collapsed");
    uncollapse(element.parentElement.closest("li"));
  }
};

/**
 * Find the deepest opened directory
 * @param {string[]} path Current path we are looking at, init with fullpath
 * @param {NodeListOf<ChildNode>} options Options we have, init with list root
 * @returns
 */
const deepestNodeOpened = (path, options) => {
  if (path[0] === "") {
    return options[0].parentNode.parentNode;
  }

  // Iterate over possible options
  for (let i = 0; i < options.length; ++i) {
    // If the directory and the current path match
    if (decodeURI(path[0]) === options[i].firstChild.nodeValue) {
      if (path.length === 1) {
        // We found it
        return options[i];
      }

      // Continue the search
      return deepestNodeOpened(
        path.slice(1),
        options[i].querySelector("ul").childNodes
      );
    }
  }
};

const searchFiles = (query, parent, currentFile) => {
  // Prevent blocking the main thread
  requestAnimationFrame(() => {
    const children = parent.querySelectorAll("li");

    const normalizedQuery = query.toLowerCase().trim();
    if (normalizedQuery === "") {
      children.forEach((item) => {
        item.style.display = "";
        if (
          item.classList.contains("directory") &&
          !item.classList.contains("collapsed")
        ) {
          item.classList.add("collapsed");
        }
      });
      uncollapse(currentFile);
      return;
    }

    for (const item of children) {
      const matches = item.innerText.toLowerCase().includes(normalizedQuery);
      if (matches) {
        item.style.display = "";
        uncollapse(item);
        continue;
      }
      item.style.display = "none";
    }
  });
};

window.addEventListener("load", () => {
  // Build the filetree
  const fileTreeElement = document.getElementsByTagName("aside")[0];
  const dataElement = fileTreeElement.getElementsByTagName("span")[0];

  buildFileTree(
    fileTreeElement,
    JSON.parse(dataElement.getAttribute("data-json")).children,
    ""
  );
  dataElement.remove();

  // Open nested openeded directories
  const infoURL = window.location.href.split("?");
  const fullpath = infoURL.length > 1 ? infoURL[1].substring(2) : "index.md";
  const path = fullpath.substring(0, fullpath.lastIndexOf("/"));

  const currentlyOpen = deepestNodeOpened(
    path.split("/"),
    fileTreeElement.querySelector("ul").childNodes
  );
  uncollapse(currentlyOpen);

  // Bold opened file
  const openedFile = decodeURI(fullpath.split("/").at(-1));
  currentlyOpen.querySelector("ul").childNodes.forEach((el) => {
    if (el.innerText === openedFile) {
      el.style.fontWeight = "bold";
    }
  });

  // Search bar hook
  document.getElementById("searchBar").addEventListener("input", (e) => {
    searchFiles(e.target.value, fileTreeElement, currentlyOpen);
  });

  // Responsive menu
  let menuOpen = false;
  const button = document.getElementById("menu");
  const content = document.getElementsByTagName("main")[0];
  const initialButtonTextContent = button.textContent;
  const resetPage = () => {
    menuOpen = !menuOpen;
    if (menuOpen) {
      fileTreeElement.style.display = "block";
      content.style.display = "none";
      button.textContent = "Fermer le menu";
      return;
    }

    fileTreeElement.style.display = "";
    content.style.display = "";
    button.textContent = initialButtonTextContent;
  };

  button.addEventListener("click", resetPage);
  window.addEventListener("resize", () => {
    if (menuOpen && window.innerWidth > 640) {
      resetPage();
    }
  });
});