import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import {
  Outlet,
  Link,
  ClientOnly,
  createRootRouteWithContext,
  useRouter,
  useRouterState,
  HeadContent,
  Scripts,
  type ErrorComponentProps,
} from "@tanstack/react-router";
import { useEffect, lazy, Suspense } from "react";


import appCss from "../styles.css?url";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { TooltipProvider } from "@/components/ui/tooltip";
import { useStoreHydration } from "@/hooks/useStoreHydration";
import { useReferralTracking } from "@/hooks/useReferralTracking";
import { trackPageView } from "@/lib/analytics";
import { getGaMeasurementId } from "@/lib/ga.functions";
import { getStringOverrides } from "@/lib/content.functions";
import { setServerStringOverrides } from "@/lib/strings";
import { langFromPath, stripLangPrefix, localizePath, headLang, useLang, useT, SITE_URL } from "@/lib/i18n";

// Below-the-fold / floating widgets — never needed for first paint, so we lazy-load
// them after hydration and skip rendering them server-side entirely. This trims the
// initial bundle, SSR HTML, and an unnecessary review-stats network request.
const CartDrawer = lazy(() => import("@/components/CartDrawer"));
const WhatsAppWidget = lazy(() => import("@/components/WhatsAppWidget"));
const ReviewsWidget = lazy(() => import("@/components/ReviewsWidget"));
// The vendor-hosted cookie banner is requested after hydration by CookieBannerBoot,
// not from <head>: React's document hydration deletes the markup it injects.
import CookieBannerBoot from "@/components/CookieBannerBoot";

/**
 * The runtime (SSR process) knows the store URL and — through the backend
 * settings — the Turnstile site key, so the browser does not have to rely on
 * build-time VITE_* values that differ per environment. This is rendered into
 * <head> so it is available before any module runs; on the client there is no
 * store URL in process.env, which is why the script is then skipped.
 */
const runtimeConfigScript = (() => {
  if (typeof process === "undefined" || !process.env) return null;

  const storeUrl = (process.env.WC_URL || process.env.WC_STORE_URL || "").replace(/\/+$/, "");
  const siteKey = process.env.TURNSTILE_SITE_KEY || "";
  const siteUrl = (process.env.SITE_URL || "").replace(/\/+$/, "");

  if (!storeUrl && !siteKey) return null;

  const config = {
    ...(storeUrl ? { graphqlUrl: `${storeUrl}/graphql` } : {}),
    ...(siteKey ? { turnstileSiteKey: siteKey } : {}),
    ...(siteUrl ? { siteUrl } : {}),
  };

  return `window.__PW_CONFIG__=${JSON.stringify(config)};`;
})();



function NotFoundComponent() {
  const t = useT();
  return (
    <div className="flex min-h-screen items-center justify-center bg-background px-4">
      <div className="max-w-md text-center">
        <h1 className="text-7xl font-bold text-foreground">404</h1>
        <h2 className="mt-4 text-xl font-semibold text-foreground">{t("Pagina niet gevonden", "Page not found")}</h2>
        <p className="mt-2 text-sm text-muted-foreground">
          {t("De pagina die je zoekt bestaat niet of is verplaatst.", "The page you are looking for doesn't exist or has been moved.")}
        </p>
        <div className="mt-6">
          <Link
            to="/"
            className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
          >
            {t("Naar home", "Go to home")}
          </Link>
        </div>
      </div>
    </div>
  );
}

function ErrorComponent({ error, reset }: ErrorComponentProps) {
  console.error(error);
  const router = useRouter();
  const t = useT();
  return (
    <div className="flex min-h-screen items-center justify-center bg-background px-4">
      <div className="max-w-md text-center">
        <h1 className="text-xl font-semibold tracking-tight text-foreground">
          {t("Deze pagina kon niet geladen worden", "This page could not be loaded")}
        </h1>
        <p className="mt-2 text-sm text-muted-foreground">
          {t("Er ging iets mis aan onze kant. Probeer het opnieuw of ga terug naar home.", "Something went wrong on our end. Please try again or go back to home.")}
        </p>
        <div className="mt-6 flex flex-wrap justify-center gap-2">
          <button
            onClick={() => {
              router.invalidate();
              reset();
            }}
            className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
          >
            {t("Opnieuw proberen", "Try again")}
          </button>
          <a
            href="/"
            className="inline-flex items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-accent"
          >
            {t("Naar home", "Go to home")}
          </a>
        </div>
      </div>
    </div>
  );
}

export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
  loader: async () => {
    // The panel's text overrides travel with the page, so the server render and the
    // browser hydration use the same dictionary (see src/lib/strings.ts).
    const strings = await getStringOverrides().catch(() => null);

    setServerStringOverrides(strings);

    try {
      return { gaId: await getGaMeasurementId(), strings };
    } catch {
      return { gaId: null, strings };
    }
  },
  staleTime: Infinity,
  beforeLoad: ({ location }) => ({
    lang: langFromPath(new URL(location.publicHref, SITE_URL).pathname),
  }),
  head: (ctx) => {
    const { loaderData, matches } = ctx;
    const lang = headLang(ctx);
    const leafPath = stripLangPrefix(matches[matches.length - 1]?.pathname ?? "/");
    const defTitle = lang === "en" ? "Peptidewinkel — Research-grade peptides, shipped discreetly" : "Peptidewinkel — Research-grade peptides, discreet verzonden";
    const defDesc = lang === "en" ? "Peptidewinkel supplies research-grade peptides by Alpha BioPharma with public Janoshik lab reports. Discreetly packed, fast shipping within Europe." : "Peptidewinkel levert research-grade peptides van Alpha BioPharma met openbare Janoshik-labrapporten. Discreet verpakt, snelle verzending binnen Europa.";
    const gaId = loaderData?.gaId ?? null;
    // Consent Mode v2 default — everything denied until the vendor cookie
    // banner (loaded below) records the visitor's choice and issues its own
    // gtag('consent','update', ...). Emitted synchronously in <head> so GTM
    // sees the denied signals before any tag evaluates.
    const consentDefaultScript =
      "window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}window.gtag=gtag;" +
      "gtag('consent','default',{ad_storage:'denied',ad_user_data:'denied',ad_personalization:'denied',analytics_storage:'denied',functionality_storage:'granted',security_storage:'granted',wait_for_update:500});";
    // Text overrides edited in the admin panel. Injected as a global (rather than
    // fetched) so the browser has them before the first render: the server render
    // and the hydration then produce identical markup. Only emitted on the server;
    // on the client the global is already there.
    const strings = loaderData?.strings ?? null;
    const stringsScript =
      typeof window === "undefined" &&
      strings &&
      (Object.keys(strings.nl).length > 0 || Object.keys(strings.en).length > 0)
        ? `window.__PW_STRINGS__=${JSON.stringify(strings)};`
        : null;
    return {
      meta: [
        { charSet: "utf-8" },
        { name: "viewport", content: "width=device-width, initial-scale=1" },
        { title: defTitle },
        { name: "description", content: defDesc },
        { name: "author", content: "Peptidewinkel" },
        { property: "og:site_name", content: "Peptidewinkel" },
        { property: "og:type", content: "website" },
        { property: "og:locale", content: lang === "en" ? "en_GB" : "nl_NL" },
        { name: "twitter:card", content: "summary_large_image" },
        { property: "og:title", content: defTitle },
        { name: "twitter:title", content: defTitle },
        { property: "og:description", content: defDesc },
        { name: "twitter:description", content: defDesc },
      ],
      links: [
        { rel: "stylesheet", href: appCss },
        { rel: "alternate", hrefLang: "nl", href: `${SITE_URL}${localizePath(leafPath, "nl")}` },
        { rel: "alternate", hrefLang: "en", href: `${SITE_URL}${localizePath(leafPath, "en")}` },
        { rel: "alternate", hrefLang: "x-default", href: `${SITE_URL}${leafPath}` },
        { rel: "icon", href: "/favicon.png", type: "image/png" },
        { rel: "preconnect", href: "https://fonts.googleapis.com" },
        { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" },
        {
          rel: "preload",
          as: "style",
          href: "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Sora:wght@600;700;800&display=swap",
        },
        {
          rel: "stylesheet",
          href: "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Sora:wght@600;700;800&display=swap",
        },

      ],
      scripts: [
        ...(stringsScript ? [{ children: stringsScript }] : []),
        { children: consentDefaultScript },
        ...(runtimeConfigScript ? [{ children: runtimeConfigScript }] : []),
        // GTM loads on every page and respects the consent signals above.
        {
          children:
            "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-53LRSLST');",
        },
        // Direct GA4 via gtag.js (measurement ID from project settings).
        ...(gaId
          ? [
              { src: `https://www.googletagmanager.com/gtag/js?id=${gaId}`, async: true },
              {
                children: `window.__gaId=${JSON.stringify(gaId)};gtag('js',new Date());gtag('config',${JSON.stringify(gaId)},{send_page_view:false});`,
              },
            ]
          : []),
      ],
    };
  },
  shellComponent: RootShell,
  component: RootComponent,
  notFoundComponent: NotFoundComponent,
  errorComponent: ErrorComponent,
});

function RootShell({ children }: { children: React.ReactNode }) {
  const lang = useLang();
  return (
    <html lang={lang}>
      <head>
        <HeadContent />
      </head>
      <body>
        <noscript>
          <iframe
            src="https://www.googletagmanager.com/ns.html?id=GTM-53LRSLST"
            height="0"
            width="0"
            style={{ display: "none", visibility: "hidden" }}
          />
        </noscript>
        {children}
        <Scripts />
      </body>
    </html>
  );
}

function RootComponent() {
  const { queryClient } = Route.useRouteContext();
  useStoreHydration();
  useReferralTracking();

  // SPA page views for GA4 (GTM only sees the first load on its own).
  const pathname = useRouterState({ select: (s) => s.location.pathname });
  useEffect(() => {
    const t = setTimeout(() => trackPageView(pathname), 50); // let head() update the title
    return () => clearTimeout(t);
  }, [pathname]);

  return (
    <QueryClientProvider client={queryClient}>
      <TooltipProvider>
        <div className="min-h-screen flex flex-col">
          <Header />
          <main className="flex-1">
            <Outlet />
          </main>
          <Footer />
        </div>
        <ClientOnly fallback={null}>
          <Suspense fallback={null}>
            <CartDrawer />
            <WhatsAppWidget />
            <ReviewsWidget />
          </Suspense>
        </ClientOnly>
        <CookieBannerBoot />
      </TooltipProvider>
    </QueryClientProvider>
  );
}

