<script lang="ts">
  import { onMount, onDestroy, setContext } from "svelte";
  import { goto } from "$app/navigation";
  import { page } from "$app/stores";
  import { isAuthenticated, isLoading as isAuthLoading } from "$lib/stores/auth";
  import { library } from "$lib/stores/library";
  import { useScrollGuard } from "$lib/composables/useScrollGuard";
  import Search from "$lib/components/Search.svelte";
  import SearchScopeChips from "$lib/components/search/SearchScopeChips.svelte";
  import { resolveSearchScope, type SearchScope } from "$lib/utils/searchScope";
  import AppHeader from "$lib/components/AppHeader.svelte";
  import BottomUi from "$lib/components/BottomUi.svelte";
  import SleepTimerModal from "$lib/components/player/SleepTimerModal.svelte";

  // Scroll guard prevents accidental taps on library cards during/after scrolling (Android)
  const scrollGuard = useScrollGuard(300);
  setContext("scrollGuard", scrollGuard);

  let { children } = $props();

  let searchQuery = $state("");
  let showSleepTimerModal = $state(false);

  onMount(() => {
    return () => {
      scrollGuard.cleanup();
    };
  });

  // Redirect to login if not authenticated
  $effect(() => {
    if (!$isAuthLoading && !$isAuthenticated) {
      goto("/");
    }
  });

  // The header search outlives navigation, so the route seeds the scope only
  // while no search is active. Once the user has typed (or picked a chip),
  // their scope governs until they clear the query — navigating must not snap
  // a widened search back to the section they happen to be in.
  // TRACES: UR-049 | DR-064
  let searchScope = $state<SearchScope>(resolveSearchScope($page.url.pathname));

  $effect(() => {
    const pathname = $page.url.pathname;
    if (!searchQuery.trim()) {
      searchScope = resolveSearchScope(pathname);
    }
  });

  async function handleSearch(query: string) {
    if (query.trim()) {
      await library.search(query, searchScope);
    } else {
      library.clearSearch();
    }
  }

  async function handleScopeChange(next: SearchScope) {
    searchScope = next;
    if (searchQuery.trim()) {
      await library.search(searchQuery, next);
    }
  }
</script>

{#if $isAuthLoading}
  <div class="min-h-screen flex items-center justify-center">
    <div class="w-8 h-8 border-2 border-[var(--color-jellyfin)] border-t-transparent rounded-full animate-spin"></div>
  </div>
{:else if $isAuthenticated}
  <div class="h-screen flex flex-col overflow-hidden">
    <!-- Header (shared across all authenticated chrome; library supplies search) -->
    <AppHeader search={librarySearch} />

    {#snippet librarySearch()}
      <Search
        bind:value={searchQuery}
        placeholder="Search your library..."
        onSearch={handleSearch}
      />
      {#if searchQuery.trim()}
        <SearchScopeChips scope={searchScope} onChange={handleScopeChange} />
      {/if}
    {/snippet}

    <!-- Main content. The BottomUi below is an in-flow flex sibling, so this
         scroller is physically bounded above it and its last row can never
         render behind the nav — no measurement, no reserved padding. -->
    <main
      class="flex-1 overflow-y-auto p-4 min-h-0"
      style="overscroll-behavior: contain"
      onscroll={scrollGuard.onScroll}
    >
      {@render children()}
    </main>

    <!-- Bottom UI (mini player + nav), in-flow below the scroller. -->
    <BottomUi />

    <!-- Sleep Timer Modal -->
    <SleepTimerModal
      isOpen={showSleepTimerModal}
      onClose={() => showSleepTimerModal = false}
    />
  </div>
{/if}
