/**
 * HydratedIsland — SSR-hydrated React island wrapper.
 *
 * Composes:
 *  1. `QueryClientProvider` — shares the global browser QueryClient singleton.
 *  2. `HydrationBoundary` — hydrates prefetched query data from SSR.
 *  3. `LocaleProvider` — reads locale/dir/fontScale from Zustand store, which
 *     seeds itself from `<html lang>` on mount (set by Astro locale middleware).
 *     Pass `locale` when the island is SSR-rendered inside a page that has a
 *     server-resolved locale (e.g. login, club, cart) so that the first
 *     server render and client hydration use the correct locale — prevents
 *     Hebrew strings appearing on EN-locale pages before hydration.
 *     Omit when the island is purely client-only (no meaningful SSR output).
 *  4. `ErrorBoundary` — catches render errors, shows ErrorState with retry.
 *
 * Usage in Astro frontmatter:
 *
 *   const { dehydratedState } = await dehydrateForIsland([prefetchCart(Astro)]);
 *   ---
 *   <HydratedIsland dehydratedState={dehydratedState} locale={locale} client:idle>
 *     <CartPage />
 *   </HydratedIsland>
 *
 * Island consumes data via `useQuery({ queryKey: qk.cart(), queryFn: apiFetchCart })`.
 * Because the key matches the prefetch key, data is instantly available — no spinner.
 */

import React, { useState, type ReactNode } from 'react';
import {
  QueryClientProvider,
  HydrationBoundary,
  type DehydratedState,
} from '@tanstack/react-query';
import { LocaleProvider } from '@/lib/i18n/react';
import type { Locale } from '@/lib/i18n';
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import { LoadingOverlay } from '@/components/ui/feedback/LoadingOverlay';
import { getBrowserQueryClient, createBrowserQueryClient } from '@/lib/query/client';
import { useLiveNotifications } from '@/lib/hooks/use-live-notifications';

/**
 * Mounts the live-notification WebSocket manager inside the QueryClientProvider tree.
 * Renders nothing — side-effects only. Placed once per HydratedIsland.
 * The singleton mount-counter in use-live-notifications ensures only one socket
 * is opened even when multiple islands are mounted simultaneously.
 */
function LiveNotifMount() {
  useLiveNotifications();
  return null;
}

export interface HydratedIslandProps {
  /** Dehydrated state from `dehydrateForIsland()` in Astro frontmatter. Optional — omit for client-only islands. */
  dehydratedState?: DehydratedState;
  /**
   * Server-resolved locale from Astro frontmatter (e.g. `Astro.locals.locale ?? 'he'`).
   * When provided, seeds `LocaleProvider` so SSR + first hydration render use the
   * correct locale — eliminates Hebrew chrome on EN-locale pages before hydration.
   * After hydration the Zustand store takes over (user locale toggles propagate normally).
   */
  locale?: Locale;
  /** Static galleries can opt out of the live socket in offline previews. */
  enableLiveNotifications?: boolean;
  children: ReactNode;
}

export const HydratedIsland = React.memo(function HydratedIsland({
  dehydratedState,
  locale,
  enableLiveNotifications = true,
  children,
}: HydratedIslandProps) {
  // Stable client identity across re-renders; guards against typeof window in render body.
  const [queryClient] = useState(() =>
    typeof window === 'undefined' ? createBrowserQueryClient() : getBrowserQueryClient(),
  );
  return (
    <QueryClientProvider client={queryClient}>
      <HydrationBoundary state={dehydratedState}>
        <LocaleProvider locale={locale}>
          {enableLiveNotifications ? <LiveNotifMount /> : null}
          <ErrorBoundary>{children}</ErrorBoundary>
          <LoadingOverlay />
        </LocaleProvider>
      </HydrationBoundary>
    </QueryClientProvider>
  );
});
