let lunrIndex;
let documents = [];
let activeIndex = -1;
const searchInput = document.getElementById("search-input");
const searchBtn = document.getElementById("search-btn");
const resultsBox = document.createElement("div");
const searchForm = searchInput.closest("form");
const modal = document.createElement("div");
const modalResults = modal.querySelector("#search-modal-results");

resultsBox.id = "search-results";
document.body.appendChild(resultsBox);

modal.id = "search-modal";
modal.innerHTML = `
  <div class="search-modal-backdrop"></div>
  <div class="search-modal-content">
    <h2>Search results</h2>
    <div id="search-modal-results"></div>
  </div>
`;

document.body.appendChild(modal);

function extractDocuments(node, currentPath = "") {
  if (node.type === "folder" && node.children) {
    const nextPath = currentPath ? `${currentPath}/${node.name}` : node.name;

    node.children.forEach((child) => {
      extractDocuments(child, nextPath);
    });
  }

  if (node.type === "file") {
    documents.push({
      id: documents.length.toString(),
      title: node.name,
      content: node.content || "",
      path: node.url,
    });
  }
}

function buildIndex() {
  lunrIndex = lunr(function () {
    this.ref("id");
    this.field("title", { boost: 10 });
    this.field("url");
    this.field("content");

    documents.forEach((doc) => this.add(doc));
  });
}

async function initSearch() {
  const response = await fetch("/test.json");
  const json = await response.json();

  extractDocuments(json);
  buildIndex();
}

initSearch();

function buildExactQuery(query) {
  return query
    .toLowerCase()
    .split(/\s+/)
    .filter((term) => term.length > 1)
    .map((term) => `${term}*`)
    .join(" ");
}

function buildSnippet(content, terms, radius = 80) {
  if (!content || terms.length === 0) return "";

  const lower = content.toLowerCase();

  let index = -1;
  let matchedTerm = "";

  for (const term of terms) {
    const i = lower.indexOf(term);
    if (i !== -1 && (index === -1 || i < index)) {
      index = i;
      matchedTerm = term;
    }
  }

  if (index === -1) {
    return content.slice(0, radius * 2) + "…";
  }

  const start = Math.max(0, index - radius);
  const end = Math.min(content.length, index + matchedTerm.length + radius);

  const prefix = start > 0 ? "…" : "";
  const suffix = end < content.length ? "…" : "";

  return prefix + content.slice(start, end) + suffix;
}

function getSearchTerms(query) {
  return query
    .toLowerCase()
    .split(/\s+/)
    .filter((t) => t.length > 2);
}

function highlight(text, terms) {
  if (!text || terms.length === 0) return text;

  const escaped = terms.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));

  const regex = new RegExp(`(${escaped.join("|")})`, "gi");

  return text.replace(regex, "<mark>$1</mark>");
}

function search(query) {
  if (!lunrIndex) return [];

  const q = buildExactQuery(query);
  if (!q) return [];

  const terms = getSearchTerms(query);
  const results = lunrIndex.search(q);

  return results
    .map((r) => {
      const doc = documents.find((d) => d.id === r.ref);
      if (!doc) return null;

      const snippet = buildSnippet(doc.content, terms);

      return {
        title: highlight(doc.title, terms),
        path: doc.path,
        score: r.score,
        preview: highlight(snippet, terms),
      };
    })
    .filter(Boolean);
}

function showResults(results) {
  resultsBox.innerHTML = "";
  activeIndex = -1;

  if (results.length === 0) {
    resultsBox.style.display = "none";
    return;
  }

  const rect = searchInput.getBoundingClientRect();
  resultsBox.style.top = `${rect.bottom + window.scrollY}px`;
  resultsBox.style.left = `${rect.left + window.scrollX}px`;
  resultsBox.style.width = `${rect.width}px`;

  results.forEach((result, i) => {
    const item = document.createElement("div");
    item.className = "search-result";
    item.dataset.index = i;

    item.innerHTML = `
      <div class="search-result-title">${result.title}</div>
      <div class="search-result-preview">${result.preview}</div>
    `;

    item.onclick = () => {
      window.location.href = result.path;
    };

    resultsBox.appendChild(item);
  });

  resultsBox.style.display = "block";
}

function updateActiveResult() {
  const items = resultsBox.querySelectorAll(".search-result");

  items.forEach((item) => item.classList.remove("active"));

  if (activeIndex >= 0 && activeIndex < items.length) {
    const activeItem = items[activeIndex];

    activeItem.classList.add("active");

    activeItem.scrollIntoView({
      block: "nearest",
      behavior: "smooth",
    });
  }
}

function openSearchModal(results) {
  const modal = document.getElementById("search-modal");
  const modalResults = modal?.querySelector("#search-modal-results");
  modal.tabIndex = -1;

  if (!modal || !modalResults) {
    console.warn("Search modal not available");
    return;
  }

  modalResults.innerHTML = "";

  if (results.length === 0) {
    modalResults.innerHTML = "<p>No results found.</p>";
  }

  results.forEach((result) => {
    const item = document.createElement("div");
    item.className = "search-modal-result";
    item.innerHTML = `
      <div class="search-modal-title">${result.title}</div>
      <div class="search-modal-preview">${result.preview}</div>
    `;
    item.onclick = () => (window.location.href = result.path);
    modalResults.appendChild(item);
  });

  modal.style.display = "block";
  modal.focus();
}

function submitSearch() {
  const q = searchInput.value.trim();
  if (!q) return;
  openSearchModal(search(q));
}

/* EVENTS */
searchInput.addEventListener("keydown", (e) => {
  const items = resultsBox.querySelectorAll(".search-result");
  if (!items.length) return;

  switch (e.key) {
    case "ArrowDown":
      e.preventDefault();
      if (activeIndex < items.length - 1) {
        activeIndex++;
        updateActiveResult();
      }
      break;

    case "ArrowUp":
      e.preventDefault();
      if (activeIndex > 0) {
        activeIndex--;
        updateActiveResult();
      }
      break;

    case "Enter":
      e.preventDefault();
      if (activeIndex >= 0 && activeIndex < items.length) {
        items[activeIndex].click();
      } else {
        submitSearch();
      }
      break;

    case "Escape":
      resultsBox.style.display = "none";
      activeIndex = -1;
      break;
  }
});

document.addEventListener("click", (e) => {
  if (
    !resultsBox.contains(e.target) &&
    e.target !== searchInput &&
    e.target !== searchBtn
  ) {
    resultsBox.style.display = "none";
  }
});

modal.addEventListener("click", (e) => {
  if (e.target.classList.contains("search-modal-backdrop")) {
    modal.style.display = "none";
  }
});
modal.addEventListener("keydown", (e) => {
  if (e.key === "Escape") {
    modal.style.display = "none";
    searchInput.focus();
  }
});

window.addEventListener("pageshow", () => {
  searchInput.value = "";
  resultsBox.style.display = "none";
});
window.addEventListener("beforeunload", () => {
  searchInput.value = "";
});

if (searchForm) {
  searchForm.addEventListener("submit", (e) => {
    e.preventDefault();
    submitSearch();
  });
}

searchBtn.addEventListener("click", submitSearch);

searchInput.addEventListener("input", () => {
  const q = searchInput.value.trim();

  if (q.length < 3) {
    resultsBox.style.display = "none";
    return;
  }
  showResults(search(q));
});

/*  OLD FUNCTIONS */
function buildFuzzyQuery(query) {
  return query
    .toLowerCase()
    .split(/\s+/)
    .filter((term) => term.length > 2)
    .map((term) => `${term}~1`)
    .join(" ");
}
