import { trpc } from "@/lib/trpc";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink } from "@trpc/client";
import { createRoot } from "react-dom/client";
import superjson from "superjson";
import App from "./App";
import { Toaster } from "@/components/ui/sonner";
import { CodexProvider } from "@/contexts/CodexContext";
import { PlaylistProvider } from "@/contexts/PlaylistContext";
import { PlaylistBar } from "@/components/PlaylistBar";
import { ABTestProvider } from "@/contexts/ABTestContext";
import AffirmationToast from "@/components/AffirmationToast";
import InvestorIdentityModal from "@/components/InvestorIdentityModal";
import { ClerkAvailabilityProvider } from "@/contexts/ClerkAvailabilityContext";
import { ClerkProvider } from "@clerk/clerk-react";
import "./index.css";
import { initPerformanceMonitoring } from "@/utils/buildOptimizations";
import React, { useState, useEffect } from "react";

// ─── Web Vitals → Umami Analytics ────────────────────────────────────
declare global {
  interface Window {
    umami?: {
      track: (eventName: string, data?: Record<string, string | number>) => void;
    };
  }
}

if (import.meta.env.PROD) {
  window.addEventListener('load', () => {
    setTimeout(() => {
      initPerformanceMonitoring((name, value) => {
        if (window.umami?.track) {
          window.umami.track('web-vital', {
            metric: name,
            value: Math.round(value * 100) / 100,
            rating: getVitalRating(name, value),
            page: window.location.pathname,
          });
        }
      });
    }, 1000);
  });
}

function getVitalRating(name: string, value: number): string {
  switch (name) {
    case 'LCP':  return value <= 2500 ? 'good' : value <= 4000 ? 'needs-improvement' : 'poor';
    case 'FID':  return value <= 100  ? 'good' : value <= 300  ? 'needs-improvement' : 'poor';
    case 'CLS':  return value <= 0.1  ? 'good' : value <= 0.25 ? 'needs-improvement' : 'poor';
    case 'INP':  return value <= 200  ? 'good' : value <= 500  ? 'needs-improvement' : 'poor';
    case 'LongTask': return value <= 50 ? 'good' : value <= 100 ? 'needs-improvement' : 'poor';
    default:     return 'unknown';
  }
}

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 3 * 60 * 1000, // 3 min — prevents redundant refetches on navigation
      gcTime: 15 * 60 * 1000, // 15 min — keep data in memory longer
      refetchOnWindowFocus: false,
      refetchOnReconnect: false,
      retry: 1,
      retryDelay: (attemptIndex) => Math.min(500 * 2 ** attemptIndex, 5000), // Fast retry
    },
  },
});

queryClient.getQueryCache().subscribe(event => {
  if (event.type === "updated" && event.action.type === "error") {
    console.error("[API Query Error]", event.query.state.error);
  }
});

queryClient.getMutationCache().subscribe(event => {
  if (event.type === "updated" && event.action.type === "error") {
    console.error("[API Mutation Error]", event.mutation.state.error);
  }
});

const trpcClient = trpc.createClient({
  links: [
    httpBatchLink({
      url: "/api/trpc",
      transformer: superjson,
      maxURLLength: 2048,
      fetch(input, init) {
        return globalThis.fetch(input, {
          ...(init ?? {}),
          credentials: "include",
        }).then(async (response) => {
          const contentType = response.headers.get('content-type') || '';
          if (!response.ok && contentType.includes('text/html')) {
            const status = response.status;
            let msg = 'Server error';
            if (status === 502 || status === 503 || status === 504) {
              msg = 'The request timed out. The server may be processing a large request. Please try again.';
            } else if (status === 413) {
              msg = 'The response was too large to process.';
            }
            return new Response(
              JSON.stringify([{ error: { message: msg, code: -1, data: { code: 'TIMEOUT', httpStatus: status } } }]),
              { status: 200, headers: { 'content-type': 'application/json' } }
            );
          }
          return response;
        });
      },
    }),
  ],
});

// Performance observer — detect long tasks in development
if (typeof PerformanceObserver !== 'undefined' && !import.meta.env.PROD) {
  try {
    const longTaskObserver = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (entry.duration > 100) {
          console.warn(`[Perf] Long task: ${entry.duration.toFixed(0)}ms`, entry);
        }
      }
    });
    longTaskObserver.observe({ type: 'longtask', buffered: true });
  } catch { /* PerformanceObserver longtask not supported */ }
}

// Prefetch critical font files during idle time
if ('requestIdleCallback' in window) {
  (window as any).requestIdleCallback(() => {
    const fontUrls = [
      'https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hiA.woff2',
    ];
    fontUrls.forEach(url => {
      const link = document.createElement('link');
      link.rel = 'prefetch';
      link.as = 'font';
      link.type = 'font/woff2';
      link.crossOrigin = 'anonymous';
      link.href = url;
      document.head.appendChild(link);
    });
  });
}

// Register service worker for offline support
if ('serviceWorker' in navigator && import.meta.env.PROD) {
  window.addEventListener('load', () => {
    const register = () => {
      navigator.serviceWorker.register('/sw.js')
        .then((registration) => {
          setInterval(() => registration.update(), 60 * 60 * 1000);
        })
        .catch(() => {});
    };
    if ('requestIdleCallback' in window) {
      (window as any).requestIdleCallback(register);
    } else {
      setTimeout(register, 2000);
    }
  });
}

// ─── Clerk Configuration ─────────────────────────────────────────────
const CLERK_PK = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY || "";
const CLERK_SIGN_IN_URL = "https://marlowekeynes.org/login";
const CLERK_PRIMARY_DOMAIN = "marlowekeynes.org";

/**
 * Probe the Clerk Frontend API to check if the satellite domain is reachable.
 * Only considers Clerk available on a 2xx response to prevent loading a broken
 * ClerkProvider that hangs or crashes the page.
 */
async function probeClerkCDN(): Promise<boolean> {
  if (!CLERK_PK) return false;
  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 3000);
    const res = await fetch("https://clerk.mkcompanyhistory.com/v1/environment", {
      method: "GET",
      signal: controller.signal,
      headers: { Authorization: `Bearer ${CLERK_PK}` },
    });
    clearTimeout(timeout);
    return res.ok; // Only 2xx counts as reachable
  } catch {
    return false;
  }
}

/**
 * App tree — renders the full provider stack.
 *
 * Clerk satellite integration:
 * - Probes the Clerk Frontend API on mount to verify reachability
 * - If reachable, wraps the app in ClerkProvider with satellite config
 * - If not reachable, falls back to cookie-based tRPC auth via useAuth
 */
function AppTree() {
  const [clerkReachable, setClerkReachable] = useState<boolean | null>(null);

  useEffect(() => {
    probeClerkCDN().then(setClerkReachable);
  }, []);

  // While probing, render without Clerk (cookie auth still works)
  if (clerkReachable === null) {
    return (
      <ClerkAvailabilityProvider available={false}>
        <trpc.Provider client={trpcClient} queryClient={queryClient}>
          <QueryClientProvider client={queryClient}>
            <ABTestProvider>
              <CodexProvider>
                <PlaylistProvider>
                  <App />
                  <PlaylistBar />
                  <Toaster position="bottom-right" richColors closeButton />
                  <AffirmationToast />
                  <InvestorIdentityModal />
                </PlaylistProvider>
              </CodexProvider>
            </ABTestProvider>
          </QueryClientProvider>
        </trpc.Provider>
      </ClerkAvailabilityProvider>
    );
  }

  const inner = (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        <ABTestProvider>
          <CodexProvider>
            <PlaylistProvider>
              <App />
              <PlaylistBar />
              <Toaster position="bottom-right" richColors closeButton />
              <AffirmationToast />
              <InvestorIdentityModal />
            </PlaylistProvider>
          </CodexProvider>
        </ABTestProvider>
      </QueryClientProvider>
    </trpc.Provider>
  );

  // HIDDEN: Clerk satellite login disabled for now — re-enable this block to restore Clerk SSO
  // if (clerkReachable && CLERK_PK) {
  //   return (
  //     <ClerkProvider
  //       publishableKey={CLERK_PK}
  //       isSatellite={true}
  //       domain={CLERK_PRIMARY_DOMAIN}
  //       signInUrl={CLERK_SIGN_IN_URL}
  //       signInForceRedirectUrl={window.location.origin}
  //       afterSignOutUrl={window.location.origin}
  //     >
  //       <ClerkAvailabilityProvider available={true}>
  //         {inner}
  //       </ClerkAvailabilityProvider>
  //     </ClerkProvider>
  //   );
  // }

  return (
    <ClerkAvailabilityProvider available={false}>
      {inner}
    </ClerkAvailabilityProvider>
  );
}

createRoot(document.getElementById("root")!).render(<AppTree />);
