import AnalyticsProviders from "@/components/AnalyticsProviders";
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import {
  getLocaleKeywords,
  ogAlternateLocalesFor,
  ogImagesFor,
  ogLocaleFor,
  seo,
} from "@/config/seo";
import { site } from "@/config/site";
import { pickClientMessages } from "@/i18n/client-messages";
import { routing } from "@/i18n/routing";
import type { Metadata, Viewport } from "next";
import { hasLocale, type Locale, NextIntlClientProvider } from "next-intl";
import {
  getMessages,
  getTranslations,
  setRequestLocale,
} from "next-intl/server";
import { Montserrat, Tenor_Sans } from "next/font/google";
import { notFound } from "next/navigation";

const montserrat = Montserrat({
  subsets: ["latin"],
  display: "swap",
  weight: ["300", "400", "500", "600"],
  variable: "--font-montserrat",
});

// Display serif for editorial headings (matches the Stitch "Refined Industrial"
// reference). Single weight (400).
const tenorSans = Tenor_Sans({
  subsets: ["latin"],
  display: "swap",
  weight: ["400"],
  variable: "--font-tenor-sans",
});

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export const viewport: Viewport = {
  width: "device-width",
  initialScale: 1,
  viewportFit: "cover",
  themeColor: site.themeColor,
  colorScheme: "light",
};

export async function generateMetadata(
  props: Omit<LayoutProps<"/[locale]">, "children">,
): Promise<Metadata> {
  const { locale } = await props.params;
  const typedLocale = locale as Locale;

  const t = await getTranslations({
    locale: typedLocale,
    namespace: "LocaleLayout",
  });
  const keywords = await getLocaleKeywords(typedLocale);

  return {
    metadataBase: new URL(site.url),
    title: {
      template: seo.titleTemplate,
      default: seo.defaultTitle,
    },
    description: t("description"),
    keywords: [...keywords],
    openGraph: {
      type: seo.openGraph.type,
      siteName: seo.openGraph.siteName,
      title: seo.defaultTitle,
      description: t("description"),
      locale: ogLocaleFor(typedLocale),
      alternateLocale: ogAlternateLocalesFor(typedLocale),
      // Declared explicitly so `og:image:alt` follows the locale — see
      // `ogImagesFor`. Leaving it out would let Next inject
      // `opengraph-image.tsx` with its single, non-localisable `alt`.
      images: await ogImagesFor(typedLocale),
    },
    twitter: {
      card: seo.twitter.card,
      site: seo.twitter.site,
      title: seo.defaultTitle,
      description: t("description"),
    },
    verification: {
      google: seo.verification.google,
      other: seo.verification.bing
        ? { "msvalidate.01": seo.verification.bing }
        : undefined,
    },
    appleWebApp: {
      capable: true,
      title: site.shortName,
      statusBarStyle: "default",
    },
    icons: {
      apple: [{ url: "/apple-touch-icon.png", sizes: "180x180" }],
    },
  };
}

export default async function LocaleLayout({
  children,
  params,
}: LayoutProps<"/[locale]">) {
  const { locale } = await params;
  if (!hasLocale(routing.locales, locale)) {
    notFound();
  }

  setRequestLocale(locale);

  // Both read the same request config, so they resolve in parallel rather than
  // in a waterfall.
  const [tCommon, messages] = await Promise.all([
    getTranslations({ locale, namespace: "Common" }),
    getMessages({ locale }),
  ]);

  return (
    // Pas de `h-full` : il bornait la boite de <html> a la hauteur du viewport
    // (664px mesures pour un document de 10485px), donc a la zone de
    // positionnement du fond de canvas pose dans `globals.css`, qui n'aurait
    // jamais atteint le bas de page. `body` porte deja `min-h-dvh`, seule
    // source de la hauteur minimale ; aucun descendant ne resout un `h-full`
    // sur <body>, qui n'a pas de `height` definie.
    <html
      className={`${montserrat.variable} ${tenorSans.variable} scroll-smooth antialiased`}
      data-scroll-behavior="smooth"
      lang={locale}
    >
      {/* Pas de `font-sans` : `@layer base { html { @apply font-sans } }` est
          la source unique, et <body> en herite. */}
      <body className="flex min-h-dvh flex-col">
        {/* Skip link — first focusable element of the page (WCAG 2.4.1 A), so
            the keyboard can bypass the logo, the 8 nav links, the language
            selector, the CTA and the burger on every page. Hidden until it
            takes focus. */}
        <a
          href="#content"
          className="sr-only rounded-none focus-visible:not-sr-only focus-visible:fixed focus-visible:top-4 focus-visible:left-4 focus-visible:z-[60] focus-visible:bg-foreground focus-visible:px-5 focus-visible:py-3 focus-visible:text-label focus-visible:uppercase focus-visible:text-background focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gold"
        >
          {tCommon("skipToContent")}
        </a>
        {/* `messages` is scoped on purpose: left implicit, the provider ships the
            whole catalogue (~42 KB of JSON) in the RSC payload of every page.
            See `src/i18n/client-messages.ts` for the list and how to keep it in
            sync. Server Components are unaffected — they read the request
            config, not this provider. */}
        <NextIntlClientProvider messages={pickClientMessages(messages)}>
          <Header />
          {/* The single `main` landmark of the app: header and footer stay
              outside it. `tabIndex={-1}` lets the skip link move focus here —
              and Chrome then paints its UA focus ring around the entire page.
              `focus-visible:outline-none` drops it: this is a programmatic
              focus target, never reachable by Tab, and the skip link itself
              keeps a visible focus style, so no keyboard user loses an
              indicator. */}
          <main
            id="content"
            tabIndex={-1}
            className="flex flex-1 flex-col focus-visible:outline-none"
          >
            {children}
          </main>
          <Footer />
        </NextIntlClientProvider>
        <AnalyticsProviders />
      </body>
    </html>
  );
}
