/**
 * Clean URLs from anchors
 * @param {string} url Link URL
 * @returns Link URL cleaned
 */
const cleanURL = (url) => url.split("#")[0];

/**
 * Capitalize a text
 * @param {string} text Input text
 * @returns Capitalize text
 */
const capitalize = (text) =>
  text.length === 0 ? text : text[0].toUpperCase() + text.substring(1);

/**
 * 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 = capitalize(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 = cleanURL(window.location.href).split("?")[0];
      const a = document.createElement("a");
      a.text = capitalize(
        item.name.endsWith(".md") ? item.name.slice(0, -3) : 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 The deepest node
 */
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]).toLowerCase() ===
      options[i].firstChild.nodeValue.toLowerCase()
    ) {
      if (path.length === 1) {
        // We found it
        return options[i];
      }

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

/**
 * Search in the filetree, when nothing is aske, returns to initial state
 * @param {string} query Query
 * @param {HTMLElement} parent Filetree
 * @param {HTMLLIElement} currentFile Current file opened
 */
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 = cleanURL(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) => {
    const elementToCompare = decodeURI(
      el.firstChild.search
        ? el.firstChild.search.substring(3).split("/").at(-1)
        : el.firstChild.data
    );

    if (elementToCompare === 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();
    }
  });
});