import type { ReactNode } from "react";

import { cookies } from "next/headers";
import { redirect } from "next/navigation";

import { SIDEBAR_COLLAPSIBLE_VALUES, SIDEBAR_VARIANT_VALUES } from "@/lib/preferences/layout";
import { getPreference } from "@/server/server-actions";

import { CustomerCsrfProvider, CustomerCsrfSync } from "../_components/customer-csrf-provider";
import { CustomerLayoutShell } from "../_components/customer-layout-shell";
import { UiPrefsSessionHydrator } from "../_components/ui-prefs-session-hydrator";
import { resolveInitialMenuLayout } from "../_lib/initial-menu-layout-server";
import { PortalSessionGuard } from "@/components/auth/portal-session-guard";
import { customerSessionProfile } from "@/lib/auth/portal-session";
import { getCustomerSessionContext, getFrontendAccessToken } from "@/lib/frontend-auth/server";
import { tenantCookieName } from "@/lib/frontend-auth/constants";
import { CUSTOMER_CSRF_COOKIE } from "@/lib/server/request-guards";

type LayoutProps = {
  children: ReactNode;
  params: Promise<{ tenant: string }>;
};

export default async function TenantCustomerLayout({ children, params }: Readonly<LayoutProps>) {
  const { tenant } = await params;
  const cookieStore = await cookies();
  const defaultOpen = cookieStore.get("sidebar_state")?.value !== "false";
  const csrfCookieName = tenantCookieName(CUSTOMER_CSRF_COOKIE, tenant);
  const csrfTokenRaw = cookieStore.get(csrfCookieName)?.value ?? null;
  let csrfToken: string | null = null;
  if (csrfTokenRaw) {
    try {
      csrfToken = decodeURIComponent(csrfTokenRaw);
    } catch {
      csrfToken = csrfTokenRaw;
    }
  }
  const session = await getCustomerSessionContext(tenant);
  const sessionToken = await getFrontendAccessToken(tenant);

  // Force-revoked / expired JWT: leave the portal shell and clear cookies via bounce route.
  // Proxy only validates signature+exp, so without this the stock page stays "logged in".
  if (session.resolution === "rejected") {
    redirect(`/customer/${tenant}/guest/session-expired`);
  }
  // Only for a signed-in shell: the menu must be right on first paint, not after a browser fetch.
  const initialMenuLayout =
    session.resolution === "unauthenticated" ? null : await resolveInitialMenuLayout(tenant);
  const [cookieVariant, cookieCollapsible] = await Promise.all([
    getPreference("sidebar_variant", SIDEBAR_VARIANT_VALUES, "inset"),
    getPreference("sidebar_collapsible", SIDEBAR_COLLAPSIBLE_VALUES, "icon"),
  ]);

  // Admin impersonation keeps the admin's Appearance cookies; don't adopt the customer's.
  const adoptSessionUiPrefs = session.impersonationType !== "admin";
  const variant =
    adoptSessionUiPrefs && session.uiPrefs?.sidebar_variant
      ? session.uiPrefs.sidebar_variant
      : cookieVariant;
  const collapsible =
    adoptSessionUiPrefs && session.uiPrefs?.sidebar_collapsible
      ? session.uiPrefs.sidebar_collapsible
      : cookieCollapsible;

  const sessionUser = session.user
    ? {
        name: session.user.name?.trim() || session.user.email || "Customer",
        email: session.user.email ?? "",
        avatar: "",
      }
    : null;

  const portalActorUser = session.user
    ? {
        is_corporate_portal_actor: session.user.is_corporate_portal_actor,
        account_type: session.user.account_type,
      }
    : null;

  return (
    <CustomerCsrfProvider token={csrfToken}>
      <CustomerCsrfSync token={csrfToken} />
      <CustomerLayoutShell
        tenant={tenant}
        defaultOpen={defaultOpen}
        variant={variant}
        collapsible={collapsible}
        sessionUser={sessionUser}
        portalActorUser={portalActorUser}
        portalCapabilities={session.permissions.capabilities ?? null}
        impersonated={session.impersonated}
        impersonationType={session.impersonationType}
        impersonationOwnerName={session.impersonationOwner?.name ?? null}
        navigation={session.permissions.navigation}
        allowedRoutes={session.permissions.routes}
        initialMenuLayout={initialMenuLayout}
        canUsePortfolioScope={Boolean(session.permissions.capabilities?.portfolio_scope)}
        // The same guard, from the same code, as the staff dashboard: only the profile differs.
        // Mounted whenever there is a token to guard (like the dashboard), not only once the user
        // snapshot resolved.
        sessionGuard={
          session.resolution === "unauthenticated" ? null : (
            <PortalSessionGuard
              profile={customerSessionProfile(tenant)}
              token={sessionToken}
            />
          )
        }
      >
        <UiPrefsSessionHydrator
          uiPrefs={adoptSessionUiPrefs ? session.uiPrefs : null}
          userId={session.user?.id ?? null}
        />
        {children}
      </CustomerLayoutShell>
    </CustomerCsrfProvider>
  );
}
