import { Alpine } from "./alpine";

let searchInputTimeout: ReturnType<typeof setTimeout> | null = null;
const SEARCH_DEBOUNCE_MS = 300;
const SEARCH_MIN_CHARS = 2;

function initializeSearch(): void {
  const searchInput = document.getElementById(
    "header-search",
  ) as HTMLInputElement | null;
  const mobileSearchInput = document.getElementById(
    "header-search-mobile",
  ) as HTMLInputElement | null;

  const wireInput = (input: HTMLInputElement) => {
    input.addEventListener("input", handleSearchInput);
    input.addEventListener("keydown", handleSearchKeydown);
    input.addEventListener("focus", () => {
      if (input.value.length >= SEARCH_MIN_CHARS) {
        performSearch(input.value);
      }
    });
  };

  if (searchInput) wireInput(searchInput);
  if (mobileSearchInput) wireInput(mobileSearchInput);

  if (!searchInput && !mobileSearchInput) {
    console.warn("Search input not found");
  }

  document.addEventListener("click", (e: MouseEvent) => {
    const searchResults = document.getElementById("search-results");
    const searchInputEl = document.getElementById("header-search");
    const mobileSearchInputEl = document.getElementById("header-search-mobile");

    if (
      searchResults &&
      !searchResults.contains(e.target as Node) &&
      e.target !== searchInputEl &&
      e.target !== mobileSearchInputEl
    ) {
      hideSearchResults();
    }
  });
}

function handleSearchInput(e: Event): void {
  const target = e.target as HTMLInputElement;
  const query = target.value.trim();

  if (searchInputTimeout) {
    clearTimeout(searchInputTimeout);
  }

  if (query.length < SEARCH_MIN_CHARS) {
    hideSearchResults();
    return;
  }

  searchInputTimeout = setTimeout(() => {
    performSearch(query);
  }, SEARCH_DEBOUNCE_MS);
}

function handleSearchKeydown(e: KeyboardEvent): void {
  const searchResults = document.getElementById("search-results");
  if (!searchResults || searchResults.classList.contains("hidden")) {
    return;
  }

  const items = searchResults.querySelectorAll(".search-result-item");
  const currentIndex = parseInt(searchResults.dataset.selectedIndex || "-1");

  if (e.key === "ArrowDown") {
    e.preventDefault();
    const nextIndex = Math.min(currentIndex + 1, items.length - 1);
    selectSearchResult(items, nextIndex);
  } else if (e.key === "ArrowUp") {
    e.preventDefault();
    const prevIndex = Math.max(currentIndex - 1, -1);
    selectSearchResult(items, prevIndex);
  } else if (e.key === "Enter") {
    e.preventDefault();
    if (currentIndex >= 0 && items[currentIndex]) {
      const link = items[currentIndex].querySelector("a");
      if (link) link.click();
    }
  } else if (e.key === "Escape") {
    hideSearchResults();
  }
}

function selectSearchResult(items: NodeListOf<Element>, index: number): void {
  items.forEach((item, i) => {
    if (i === index) {
      item.classList.add("bg-opacity-80");
    } else {
      item.classList.remove("bg-opacity-80");
    }
  });

  const searchResults = document.getElementById("search-results");
  if (searchResults) {
    searchResults.dataset.selectedIndex = index.toString();
  }
}

function getActiveSearchInput(): HTMLInputElement | null {
  return (
    document.activeElement?.id === "header-search-mobile"
      ? (document.getElementById("header-search-mobile") as HTMLInputElement)
      : (document.getElementById("header-search") as HTMLInputElement)
  );
}

function performSearch(query: string): void {
  const token = localStorage.getItem("token");
  if (!token) {
    console.warn("No authentication token found");
    return;
  }

  const activeInput = getActiveSearchInput();
  const activeId = activeInput?.id || "header-search";

  showSearchLoading(activeId);

  fetch(`/api/media-items/search?q=${encodeURIComponent(query)}`, {
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
  })
    .then((response) => {
      if (response.status === 404) {
        return { error: "no results found", results: [] };
      }
      return response.json();
    })
    .then(
      (
        data:
          | { error?: string; results?: MediaItemSummary[] }
          | MediaItemSummary[],
      ) => {
        hideSearchLoading();

        const resultActiveId = getActiveSearchInput()?.id;

        if (data && "error" in data && data.error === "no results found") {
          showNoResults(query, resultActiveId);
        } else if (Array.isArray(data) && data.length > 0) {
          showSearchResults(data, query, resultActiveId);
        } else if (Array.isArray(data)) {
          showNoResults(query, resultActiveId);
        } else {
          showNoResults(query, resultActiveId);
        }
      },
    )
    .catch((error) => {
      hideSearchLoading();
      console.error("Search error:", error);
      showSearchError(getActiveSearchInput()?.id);
    });
}

function showSearchLoading(activeId?: string): void {
  createSearchResultsContainer(activeId);
  const searchResults = document.getElementById("search-results");
  if (!searchResults) return;

  searchResults.innerHTML = `
        <div class="p-4 text-center" style="color: var(--text-secondary)">
            <div class="inline-block animate-spin rounded-full h-6 w-6 border-b-2" style="border-color: var(--accent)"></div>
            <p class="mt-2 text-sm">Searching...</p>
        </div>
    `;
  searchResults.classList.remove("hidden");
}

function hideSearchLoading(): void {}

function showSearchResults(results: MediaItemSummary[], query: string, activeId?: string): void {
  createSearchResultsContainer(activeId);
  const searchResults = document.getElementById("search-results");
  if (!searchResults) return;

  searchResults.dataset.selectedIndex = "-1";

  let html = `
        <div class="p-3 border-b" style="border-color: var(--border)">
            <p class="text-xs font-semibold uppercase tracking-wide" style="color: var(--text-secondary)">
                ${results.length} result${results.length !== 1 ? "s" : ""} for "${searchEscapeHtml(query)}"
            </p>
        </div>
        <div class="max-h-96 overflow-y-auto">
    `;

  results.forEach((item, index) => {
    const titleHtml = highlightMatch(item.title, query);
    const authorHtml = item.author ? highlightMatch(item.author, query) : "";
    const coverUrl = item.cover_image_path || "/static/placeholder-book.svg";

    html += `
            <div class="search-result-item p-3 border-b hover:bg-opacity-50 transition-colors cursor-pointer"
                 style="border-color: var(--border); background-color: var(--bg-secondary)"
                 data-index="${index}">
                <a href="/media/${item.id}" class="block">
                    <div class="flex items-start space-x-3">
                        <div class="w-10 h-14 flex-shrink-0 rounded overflow-hidden bg-gradient-to-br from-gray-700 to-gray-900">
                            <img src="${coverUrl}"
                                 alt="${searchEscapeHtml(item.title)}"
                                 class="w-full h-full object-cover"
                                 loading="lazy"
                                 onerror="this.src='/static/placeholder-book.svg'">
                        </div>
                        <div class="flex-1 min-w-0">
                            <h4 class="text-sm font-medium truncate" style="color: var(--text-primary)">
                                ${titleHtml}
                            </h4>
                            ${authorHtml ? `<p class="text-xs truncate" style="color: var(--text-secondary)">${authorHtml}</p>` : ""}
                            <p class="text-xs mt-1" style="color: var(--text-secondary)">
                                ${searchEscapeHtml(item.library_name)}
                            </p>
                        </div>
                    </div>
                </a>
            </div>
        `;
  });

  html += `
        </div>
        <div class="p-2 border-t text-center" style="border-color: var(--border)">
            <p class="text-xs" style="color: var(--text-secondary)">
                Press <kbd class="px-1 py-0.5 rounded" style="background-color: var(--bg-primary)">↑↓</kbd> to navigate,
                <kbd class="px-1 py-0.5 rounded" style="background-color: var(--bg-primary)">Enter</kbd> to select
            </p>
        </div>
    `;

  searchResults.innerHTML = html;
  searchResults.classList.remove("hidden");
}

function showNoResults(query: string, activeId?: string): void {
  createSearchResultsContainer(activeId);
  const searchResults = document.getElementById("search-results");
  if (!searchResults) return;

  searchResults.innerHTML = `
        <div class="p-4 text-center">
            <div class="text-4xl mb-2">🔍</div>
            <p class="text-sm" style="color: var(--text-primary)">No results found for "${searchEscapeHtml(query)}"</p>
            <p class="text-xs mt-1" style="color: var(--text-secondary)">Try different keywords</p>
        </div>
    `;
  searchResults.classList.remove("hidden");
}

function showSearchError(activeId?: string): void {
  createSearchResultsContainer(activeId);
  const searchResults = document.getElementById("search-results");
  if (!searchResults) return;

  searchResults.innerHTML = `
        <div class="p-4 text-center">
            <div class="text-4xl mb-2">⚠️</div>
            <p class="text-sm" style="color: var(--text-primary)">Search error</p>
            <p class="text-xs mt-1" style="color: var(--text-secondary)">Please try again</p>
        </div>
    `;
  searchResults.classList.remove("hidden");
}

function hideSearchResults(): void {
  const searchResults = document.getElementById("search-results");
  if (searchResults) {
    searchResults.classList.add("hidden");
  }
}

function createSearchResultsContainer(activeId?: string): void {
  let searchResults = document.getElementById("search-results");
  if (!searchResults) {
    searchResults = document.createElement("div");
    searchResults.id = "search-results";
    searchResults.className =
      "hidden absolute z-50 w-full max-w-2xl mt-2 rounded-lg shadow-lg border";
    searchResults.style.cssText =
      "background-color: var(--bg-secondary); border-color: var(--border)";

    const searchInput = document.getElementById(
      activeId || "header-search",
    );
    if (searchInput) {
      const searchContainer = searchInput.closest(".relative");
      if (searchContainer) {
        searchContainer.appendChild(searchResults);
      }
    }
  }
}

function highlightMatch(text: string, query: string): string {
  if (!text) return "";
  const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  const regex = new RegExp(`(${escapedQuery})`, "gi");
  return searchEscapeHtml(text).replace(
    regex,
    '<mark style="background-color: var(--accent); color: var(--bg-primary); padding: 0 2px; border-radius: 2px;">$1</mark>',
  );
}

function searchEscapeHtml(text: string): string {
  const div = document.createElement("div");
  div.textContent = text;
  return div.innerHTML;
}

export { initializeSearch };

Alpine.data("search", () => ({
  initializeSearch,
}));
