"use client";

import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { TRPCClientError } from "@trpc/client";
import { httpBatchLink, loggerLink } from "@trpc/client";
import { SessionProvider } from "next-auth/react";
import { useState } from "react";
import { trpc } from "./client.js";

function getBaseUrl() {
  if (typeof window !== "undefined") return window.location.origin;
  if (process.env["VERCEL_URL"]) return `https://${process.env["VERCEL_URL"]}`;
  return `http://localhost:${process.env["PORT"] ?? 3100}`;
}

function redirectToSignIn(): void {
  if (typeof window !== "undefined") {
    window.location.replace("/auth/signin");
  }
}

function isUnauthorizedTrpcError(error: unknown): boolean {
  return (
    error instanceof TRPCClientError &&
    (error as unknown as { data?: { code?: string } }).data?.code === "UNAUTHORIZED"
  );
}

function isIgnorableTransportError(error: unknown): boolean {
  const message =
    typeof error === "object" && error !== null && "message" in error
      ? String((error as { message?: unknown }).message ?? "")
      : "";

  return message.includes("Failed to fetch") || message.toLowerCase().includes("aborted");
}

export function TRPCProvider({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        queryCache: new QueryCache({
          onError: (error) => {
            if (isUnauthorizedTrpcError(error)) redirectToSignIn();
          },
        }),
        mutationCache: new MutationCache({
          onError: (error) => {
            if (isUnauthorizedTrpcError(error)) redirectToSignIn();
          },
        }),
        defaultOptions: {
          queries: {
            staleTime: 60_000, // 60 seconds — reduces refetches on navigation
            gcTime: 5 * 60_000, // 5 minutes — keep inactive queries in memory
            refetchOnWindowFocus: false,
            refetchOnReconnect: false,
            retry: (failureCount, error) => {
              // Never retry UNAUTHORIZED — redirect immediately instead
              if (isUnauthorizedTrpcError(error)) return false;
              // Don't retry on 4xx errors (auth, not found, bad input)
              if (error instanceof TRPCClientError) {
                const code = error.data?.httpStatus as number | undefined;
                if (code !== undefined && code >= 400 && code < 500) return false;
              }
              return failureCount < 2;
            },
          },
        },
      }),
  );

  const [trpcClient] = useState(() =>
    trpc.createClient({
      links: [
        loggerLink({
          enabled: (opts) => {
            const isDownError = opts.direction === "down" && isIgnorableTransportError(opts.result);
            if (isDownError) return false;
            if (process.env["NODE_ENV"] === "development") return true;
            return opts.direction === "down";
          },
        }),
        httpBatchLink({
          url: `${getBaseUrl()}/api/trpc`,
        }),
      ],
    }),
  );

  return (
    <SessionProvider refetchInterval={15 * 60}>
      <trpc.Provider client={trpcClient} queryClient={queryClient}>
        <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
      </trpc.Provider>
    </SessionProvider>
  );
}
