// @feature: email-verification/host
/**
 * EmailVerificationBannerHost — React island that drives the email-verification banner.
 *
 * Two data sources, decided at first render and stable for page lifetime:
 *   1. Anon-shell routes (edge-cached HTML, see edge-cache.ts): BaseLayout
 *      intentionally skips the __EV__ inject to avoid leaking the first authed
 *      visitor's email into every subsequent anon hit. We fetch per-user data
 *      client-side via /api/me/page-data (per-user cache key).
 *   2. All other routes: BaseLayout injects window.__EV__ server-side for
 *      unverified logged-in users.
 *
 * Resend POSTs to /api/auth/email-verification/send with x-csrf-token header
 * (CSRF middleware enforces this on all mutating routes).
 */

'use client';

import { useState, useSyncExternalStore } from 'react';
import { EmailVerificationBanner } from '@/components/ui/feedback/EmailVerificationBanner/EmailVerificationBanner';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';
import { usePersonalization } from '@/lib/hooks/usePersonalization';
import { HydratedIsland } from '@/components/HydratedIsland';

declare global {
  interface Window {
    __EV__?: { email: string; emailVerifiedAt: string | null };
  }
}

const ANON_SHELL_PATTERNS = [
  /^\/$/,
  /^\/category\/[^/]+\/?$/,
  /^\/tag\/[^/]+\/?$/,
  /^\/(?:[a-z]{2}\/)?deals?\/[^/]+\/?$/,
  /^\/search\/?$/,
];

function isAnonShellRoute(pathname: string): boolean {
  return ANON_SHELL_PATTERNS.some((re) => re.test(pathname));
}

type EvData = NonNullable<Window['__EV__']>;

function FallbackFromPageData({ route }: { route: string }) {
  const { data } = usePersonalization(route);
  if (!data?.ev) return null;
  return <Banner ev={data.ev} />;
}

// Stable no-op subscribe: store never changes after mount.
const _noop = () => () => {};

function Inner() {
  // SSR-safe: server snapshot returns undefined; client snapshot reads window globals.
  // During hydration React uses the server snapshot → renders null → matches SSR.
  // Post-hydration React switches to the client snapshot and shows the banner if needed.
  const ev = useSyncExternalStore<EvData | undefined>(
    _noop,
    () => window.__EV__,
    () => undefined,
  );
  const pathname = useSyncExternalStore<string>(
    _noop,
    () => window.location.pathname,
    () => '',
  );

  if (ev) return <Banner ev={ev} />;
  if (pathname && isAnonShellRoute(pathname)) {
    return <FallbackFromPageData route={pathname} />;
  }
  return null;
}

export function EmailVerificationBannerHost() {
  return (
    <HydratedIsland>
      <Inner />
    </HydratedIsland>
  );
}

function Banner({ ev }: { ev: EvData }) {
  const [resending, setResending] = useState(false);

  if (ev.emailVerifiedAt) return null;

  async function handleResend(): Promise<void> {
    setResending(true);
    try {
      await fetch('/api/auth/email-verification/send', {
        method: 'POST',
        credentials: 'include',
        headers: {
          'x-csrf-token': getCsrfToken(),
        },
      });
    } catch (err) {
      captureCaught(err, {
        scope: 'features.email-verification.host.resend',
        severity: 'warning',
      });
    } finally {
      setResending(false);
    }
  }

  return <EmailVerificationBanner email={ev.email} onResend={handleResend} resending={resending} />;
}
