import type { Metadata } from 'next';
import { cookies } from 'next/headers';
import ReactDOM from 'react-dom';
import '@/styles/tailwind.css';
import ClientToaster from '@client/components/ui/ClientToaster';
import { AuthProvider } from '@client/contexts/AuthContext';
import { LanguageProvider } from '@client/contexts/LanguageContext';
import { LANG_COOKIE, DEFAULT_LANG, isRtlLang } from '@client/contexts/languageConstants';
import { loadServerBranding, buildBrandingCss, DEFAULT_SITE_TITLE } from '@server/branding/loader';

export const revalidate = 60;

const DEFAULT_DESCRIPTION = 'AI-powered voice and chat agents for restaurant orders and table bookings';

export async function generateMetadata(): Promise<Metadata> {
  const { branding, version } = await loadServerBranding();
  const title = branding.site_title || DEFAULT_SITE_TITLE;
  return {
    title,
    description: DEFAULT_DESCRIPTION,
    // Always route the favicon through /favicon.ico so the dynamic route
    // handler is the single source of truth for fallback, caching, and
    // SSRF/path-traversal hardening. The ?v=<hash> busts the browser cache
    // whenever an admin uploads new branding so the new icon shows up on
    // the next page load instead of waiting for the stale cached entry.
    icons: { icon: `/favicon.ico?v=${version}` },
  };
}

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  // Emit Google Fonts preconnects via React 19's resource API instead of JSX
  // <link> elements. Rendering <link rel="preconnect"> inside our explicit
  // <head> block caused a hydration mismatch: React 19 matches hoistable
  // <link> nodes by resource identity (href/rel) rather than DOM position,
  // which shifts the positional index of the adjacent non-hoistable <script>
  // and <style> tags and triggers "Hydration failed" on every page load.
  // ReactDOM.preconnect() emits the hint via React's resource system without
  // creating a reconciled JSX node, so nothing can drift.
  ReactDOM.preconnect('https://fonts.googleapis.com');
  ReactDOM.preconnect('https://fonts.gstatic.com', { crossOrigin: 'anonymous' });

  const { branding, version } = await loadServerBranding();
  const brandingCss = buildBrandingCss(branding);
  const fontFamily = branding.site_font_family;
  const fontHref = fontFamily
    ? `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontFamily)}:wght@400;500;600;700&display=swap`
    : null;

  // Read the language cookie on the server so the very first SSR pass renders
  // the same `<html lang>`/`dir` and `body` class as the first client render.
  // This eliminates the hydration mismatch that was caused by an inline
  // bootstrap script mutating <html> before React hydrated.
  const cookieStore = await cookies();
  const initialLang = cookieStore.get(LANG_COOKIE)?.value || DEFAULT_LANG;
  const initialDir = isRtlLang(initialLang) ? 'rtl' : 'ltr';
  const bodyClass = isRtlLang(initialLang) ? 'antialiased rtl-mode' : 'antialiased';

  // Load the brand font as a React 19 resource. ReactDOM.preinit emits a
  // <link rel="stylesheet"> via React's resource system (matched by href
  // identity during hydration, never by DOM position) and does NOT call
  // document.head.appendChild, so no unexpected DOM node appears before
  // React hydrates. This replaces the previous <script dangerouslySetInnerHTML>
  // approach that was injecting the link at parse time and shifting the
  // positional index of every non-hoistable <head> sibling, causing a
  // guaranteed hydration mismatch on every page load.
  if (fontHref) {
    ReactDOM.preinit(fontHref, { as: 'style' });
  }

  return (
    <html lang={initialLang} dir={initialDir} suppressHydrationWarning>
      {/*
        No explicit <head> block. Next.js App Router manages <head> entirely
        through generateMetadata() and its own resource-injection pipeline.
        All our previous <head> children (font script, brand style tags) have
        been moved to safer alternatives above (ReactDOM.preinit / body styles)
        to eliminate React head reconciliation positional-mismatch errors.
      */}
      <body
        className={bodyClass}
        data-branding-version={version}
        suppressHydrationWarning
      >
        {/*
          Inline brand styles as the first children of <body> rather than
          inside <head>. CSS <style> elements in <body> are valid HTML5 and
          apply to the entire document. Moving them here puts them in the
          predictable <body> reconciliation tree — no framework-injected
          elements interleave with ours, so React's positional matching is
          stable on every render. They still appear before any content in the
          SSR HTML so brand colors and font render on the very first paint.
        */}
        {brandingCss && (
          <style
            id="ra-brand-vars"
            dangerouslySetInnerHTML={{ __html: brandingCss }}
          />
        )}
        {fontFamily && (
          <style
            dangerouslySetInnerHTML={{
              __html: `html,body{font-family:'${fontFamily.replace(/['"\\]/g, '')}', system-ui, sans-serif;}`,
            }}
          />
        )}
        <LanguageProvider initialLang={initialLang}>
          <AuthProvider>
            {children}
          </AuthProvider>
        </LanguageProvider>
        <ClientToaster />
      </body>
    </html>
  );
}
