import { httpBatchLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type ReactNode,
} from "react";
import SuperJSON from "superjson";

import { useAccounts } from "@/contexts/AccountsContext";
import { useAuthClient, useSession } from "@/contexts/AuthContext";
import { getAuthCookieHeaders } from "@/lib/auth-cookie";
import { performAuthReset } from "@/lib/auth-session";
import { createAppQueryClient } from "@/lib/query-client";
import type { AppRouter } from "beenvoice/server/api/root";

export const api = createTRPCReact<AppRouter>();

export function TRPCProvider({
  apiUrl,
  children,
}: {
  apiUrl: string;
  children: ReactNode;
}) {
  const authClient = useAuthClient();
  const { authStoragePrefix, activeAccountId, clearActiveAccount } =
    useAccounts();
  const { refetch } = useSession();
  const authStoragePrefixRef = useRef(authStoragePrefix);
  authStoragePrefixRef.current = authStoragePrefix;

  const mountedRef = useRef(true);
  const resettingRef = useRef(false);

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);

  const handleUnauthorized = useCallback(async () => {
    if (!activeAccountId || resettingRef.current || !mountedRef.current) return;

    const session = await authClient.getSession();
    if (session.data?.user || !mountedRef.current) return;

    resettingRef.current = true;
    try {
      await performAuthReset({
        authClient,
        clearActiveAccount,
        activeAccountId,
        refetchSession: refetch,
      });
    } finally {
      resettingRef.current = false;
    }
  }, [authClient, clearActiveAccount, activeAccountId, refetch]);

  const onUnauthorizedRef = useRef(handleUnauthorized);
  onUnauthorizedRef.current = handleUnauthorized;

  const [queryClient] = useState(() =>
    createAppQueryClient(() => {
      void onUnauthorizedRef.current();
    }),
  );

  const [trpcClient] = useState(() =>
    api.createClient({
      links: [
        httpBatchLink({
          url: `${apiUrl}/api/trpc`,
          transformer: SuperJSON,
          headers() {
            return getAuthCookieHeaders(
              authClient,
              authStoragePrefixRef.current,
            );
          },
        }),
      ],
    }),
  );

  return (
    <api.Provider client={trpcClient} queryClient={queryClient}>
      {children}
    </api.Provider>
  );
}
