<!--
  The header search box (md+ only; below md the bottom-nav Search tab and the
  /search page's own input serve that role).

  One box, one results surface. The bar renders on the library routes *and on
  /search itself*, so searching from the header no longer swaps you onto a
  screen whose input is somewhere else: the box you typed in stays where it is
  and keeps driving the results. Off /search it navigates there (the only
  surface that renders results); on /search it republishes the query into the
  URL, which the page consumes.

  TRACES: UR-049, UR-054 | DR-063, DR-064, DR-147
-->
<script lang="ts">
  import { onMount, tick } from "svelte";
  import { goto } from "$app/navigation";
  import { page } from "$app/stores";
  import { library } from "$lib/stores/library";
  import Search from "$lib/components/Search.svelte";
  import {
    isSearchRoute,
    parseSearchScope,
    resolveSearchScope,
    searchRouteUrl,
    type SearchScope,
  } from "$lib/utils/searchScope";

  // Seeded from the URL, then owned by the user. A navigation to /search
  // remounts this component (library and root render their own AppHeader), so
  // reading `?q=` here is what carries a half-typed query across that hop.
  let value = $state($page.url.searchParams.get("q") ?? "");
  let inputEl = $state<HTMLInputElement | null>(null);

  let scope = $state<SearchScope>(
    isSearchRoute($page.url.pathname)
      ? parseSearchScope($page.url.searchParams.get("scope"))
      : resolveSearchScope($page.url.pathname)
  );

  $effect(() => {
    const url = $page.url;
    if (isSearchRoute(url.pathname)) {
      // On /search the scope chips own the scope and publish it in the URL, so
      // the bar follows rather than overriding it on the next keystroke.
      scope = parseSearchScope(url.searchParams.get("scope"));
    } else if (!value.trim()) {
      // Elsewhere the route seeds the scope, but only while no search is
      // active: navigating must not snap a widened search back to the section
      // the user happens to be in.
      scope = resolveSearchScope(url.pathname);
    }
  });

  // Landing on /search with a seeded query means the user was mid-type in the
  // previous route's header. That box is gone; put the caret back in this one
  // so their next keystroke lands in the search field and not nowhere.
  onMount(async () => {
    if (!value) return;
    await tick();
    inputEl?.focus();
    inputEl?.setSelectionRange(value.length, value.length);
  });

  async function handleSearch(query: string) {
    if (isSearchRoute($page.url.pathname)) {
      // Already on the results surface — republish in place. replaceState keeps
      // a whole session of typing to a single history entry.
      await goto(searchRouteUrl(query, scope), {
        replaceState: true,
        keepFocus: true,
        noScroll: true,
      });
      return;
    }
    if (!query.trim()) {
      library.clearSearch();
      return;
    }
    await goto(searchRouteUrl(query, scope));
  }
</script>

<Search
  bind:value
  bind:inputEl
  placeholder="Search your library..."
  onSearch={handleSearch}
/>
