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 "./index.css";
import { initPerformanceMonitoring } from "@/utils/buildOptimizations";

// ─── 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") {
    const key = event.query.queryKey;
    const route = Array.isArray(key?.[0]) ? key[0].join(".") : String(key?.[0] ?? "unknown");
    console.error(`[API Query Error] ${route}`, 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);
    }
  });
}

/**
 * App tree, renders the full provider stack.
 * Authentication uses the stable cookie-based tRPC flow. Clerk availability
 * remains explicit so hooks never attempt to access an unmounted provider.
 */
function AppTree() {
  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>
  );

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

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