<script lang="ts">
  import { onMount, onDestroy } from "svelte";
  import { page } from "$app/stores";
  import { goto } from "$app/navigation";
  import { platform } from "@tauri-apps/plugin-os";
  import "../app.css";
  import { auth, needsReauth, isAuthenticated } from "$lib/stores/auth";
  import { connectivity, isConnected } from "$lib/stores/connectivity";
  import { initPlayerEvents, cleanupPlayerEvents } from "$lib/services/playerEvents";
  import { initDownloadEvents, cleanupDownloadEvents } from "$lib/stores/downloads";
  import { syncService } from "$lib/services/syncService";
  import { playbackMode } from "$lib/stores/playbackMode";
  import { sessions } from "$lib/stores/sessions";
  import { currentMedia, isPlaying, playbackPosition, playbackDuration } from "$lib/stores/player";
  import ReauthModal from "$lib/components/auth/ReauthModal.svelte";
  import Toast from "$lib/components/Toast.svelte";
  import MiniPlayer from "$lib/components/player/MiniPlayer.svelte";
  import SleepTimerModal from "$lib/components/player/SleepTimerModal.svelte";
  import BottomNav from "$lib/components/BottomNav.svelte";
  import { isInitialized, pendingSyncCount, isAndroid, showSleepTimerModal, bottomUiHeight } from "$lib/stores/appState";
  // Shuffle/repeat/next/previous come from the event-driven queue store, the
  // single source of truth (updated instantly on queue_changed).
  import { isShuffle as shuffle, repeatMode as repeat, hasNext, hasPrevious } from "$lib/stores/queue";

  let { children } = $props();

  // The fixed bottom UI (mini player stacked over the bottom nav) is measured in
  // real time and its height published to `bottomUiHeight`, so pages can reserve
  // exactly that much space instead of guessing fixed rem values.
  let bottomUiEl = $state<HTMLElement | null>(null);

  // Route-level visibility for the fixed bottom UI (the mini player itself also
  // self-gates on playback state; when it renders nothing the in-flow slot
  // collapses to 0 and the ResizeObserver shrinks the reserved padding).
  const pathname = $derived($page.url.pathname);
  const showBottomNav = $derived(
    $isAuthenticated && !pathname.startsWith('/player/') && !pathname.startsWith('/login')
  );
  const showGlobalMiniPlayer = $derived(
    !pathname.startsWith('/player/') &&
      !pathname.startsWith('/login') &&
      !pathname.startsWith('/settings') &&
      ($isAndroid || !pathname.startsWith('/library'))
  );

  $effect(() => {
    const el = bottomUiEl;
    if (!el) {
      bottomUiHeight.set(0);
      return;
    }
    const ro = new ResizeObserver((entries) => {
      bottomUiHeight.set(entries[0]?.contentRect.height ?? el.offsetHeight);
    });
    ro.observe(el);
    bottomUiHeight.set(el.offsetHeight);
    return () => {
      ro.disconnect();
      bottomUiHeight.set(0);
    };
  });

  onMount(async () => {
    // Detect platform first (synchronously, before any await) so the global
    // mini player's Android visibility gate is correct from the first render.
    // Android needs the global mini player because the library layout hides its
    // own; if this ran after `await auth.initialize()` the store stayed false
    // long enough that the mini player never appeared on library routes.
    try {
      const platformName = platform();
      isAndroid.set(platformName === "android");
    } catch (err) {
      console.error("Platform detection failed:", err);
    }

    // Initialize auth state (restore session from secure storage)
    await auth.initialize();
    isInitialized.set(true);

    // Initialize player event listener for push-based updates
    await initPlayerEvents();

    // Initialize download event listener
    await initDownloadEvents();

    // Start sync service for offline mutation queue
    syncService.start();

    // Initialize playback mode and session monitoring
    playbackMode.initializeSessionMonitoring();
    await playbackMode.refresh();
  });

  onDestroy(() => {
    cleanupPlayerEvents();
    cleanupDownloadEvents();
    connectivity.stopMonitoring();
    syncService.stop();
    auth.cleanupEventListeners();
  });

  // Connectivity monitoring is now started early in auth.initialize()
  // This effect is kept only for when the user logs in during the session
  $effect(() => {
    if ($isAuthenticated) {
      // Check if monitoring is already running by attempting to get status
      // If not running, start it (handles login during current session)
      auth.getCurrentSession().then((session) => {
        if (session?.serverUrl) {
          connectivity.forceCheck().catch((error) => {
            // If check fails, monitoring might not be started yet, so start it
            console.debug("[Layout] Queue status check failed, starting monitoring:", error);
            connectivity.startMonitoring(session.serverUrl, {
              onServerReconnected: () => {
                // Retry session verification when server becomes reachable
                auth.retryVerification();
              },
            }).catch((monitorError) => {
              console.error("[Layout] Failed to start connectivity monitoring:", monitorError);
            });
          });
        }
      });
    }
  });

  // Update pending sync count periodically
  $effect(() => {
    if ($isAuthenticated) {
      const updateCount = async () => {
        const count = await syncService.getPendingCount();
        pendingSyncCount.set(count);
      };
      updateCount();
      // Update every 10 seconds
      const interval = setInterval(updateCount, 10000);
      return () => clearInterval(interval);
    }
  });
</script>

<div class="h-screen bg-[var(--color-background)] overflow-hidden flex flex-col">
  {#if isInitialized}
    <!-- Offline indicator banner -->
    {#if $isAuthenticated && !$isConnected}
      <div class="bg-amber-600/90 text-white px-4 py-2 text-sm flex items-center justify-center gap-2 shrink-0">
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 5.636a9 9 0 010 12.728m0 0l-2.829-2.829m2.829 2.829L21 21M15.536 8.464a5 5 0 010 7.072m0 0l-2.829-2.829m-4.243 2.829a4.978 4.978 0 01-1.414-2.83m-1.414 5.658a9 9 0 01-2.167-9.238m7.824 2.167a1 1 0 111.414 1.414m-1.414-1.414L3 3m8.293 8.293l1.414 1.414" />
        </svg>
        <span>You're offline. Some features may be limited.</span>
        {#if $pendingSyncCount > 0}
          <span class="bg-white/20 px-2 py-0.5 rounded-full text-xs">
            {$pendingSyncCount} pending sync{$pendingSyncCount !== 1 ? 's' : ''}
          </span>
        {/if}
      </div>
    {/if}

    <!-- Main content -->
    <div class="flex-1 overflow-hidden">
      {@render children()}
    </div>

    <!-- Re-authentication modal -->
    <ReauthModal isOpen={$needsReauth} />

    <!-- Toast notifications (global) -->
    <Toast />

    <!-- Fixed bottom UI: mini player stacked over the bottom nav, both in normal
         flow inside one measured wrapper. The wrapper's height is observed and
         published to `bottomUiHeight` so pages reserve exactly this much space.
         Mini player is first (visually on top, above the nav). -->
    {#if showBottomNav || showGlobalMiniPlayer}
      <div bind:this={bottomUiEl} class="fixed bottom-0 left-0 right-0 z-40 flex flex-col">
        {#if showGlobalMiniPlayer}
          <MiniPlayer
            media={$currentMedia}
            isPlaying={$isPlaying}
            position={$playbackPosition}
            duration={$playbackDuration}
            shuffle={$shuffle}
            repeat={$repeat}
            hasNext={$hasNext}
            hasPrevious={$hasPrevious}
            className="flex-shrink-0"
            onExpand={() => {
              // Navigate to player page when mini player is expanded
              if ($currentMedia) {
                goto(`/player/${$currentMedia.id}`);
              }
            }}
            onSleepTimerClick={() => showSleepTimerModal.set(true)}
          />
        {/if}

        {#if showBottomNav}
          <BottomNav className="flex-shrink-0" />
        {/if}
      </div>

      <!-- Sleep Timer Modal -->
      <SleepTimerModal
        isOpen={$showSleepTimerModal}
        onClose={() => showSleepTimerModal.set(false)}
      />
    {/if}
  {:else}
    <div class="flex items-center justify-center h-screen">
      <div class="w-8 h-8 border-2 border-[var(--color-jellyfin)] border-t-transparent rounded-full animate-spin"></div>
    </div>
  {/if}
</div>
