"use client"

import {
  QueryCache,
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query"
import { httpBatchLink, loggerLink, TRPCClientError } from "@trpc/client"
import { AnyTRPCRouter } from "@trpc/server"
import { useState } from "react"

import { login } from "@/constants/routes/handleAuth"
import { env } from "@/env/client"
import { SessionExpiredError } from "@/server/errors/trpc"
import { transformer } from "@/server/transformer"

import { trpc } from "./client"

import { LangParams } from "@/types/params"

function initializeTrpcClient() {
  // Locally we set nextjs to run on port to 3000 so that we always guarantee
  //  that trpc and next are running on the same port.
  return trpc.createClient({
    links: [
      loggerLink({
        enabled: (opts) =>
          (env.NEXT_PUBLIC_NODE_ENV === "development" &&
            typeof window !== "undefined") ||
          (opts.direction === "down" && opts.result instanceof Error),
      }),
      httpBatchLink({
        fetch,
        transformer,
        /**
         * This is locally in Next.js
         */
        url: `http://localhost:${env.NEXT_PUBLIC_PORT}/api/web/trpc`,
      }),
    ],
  })
}

export default function TrpcProvider({
  children,
  lang,
}: React.PropsWithChildren<LangParams>) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        queryCache: new QueryCache({
          async onError(error) {
            if (error instanceof TRPCClientError) {
              const appError: TRPCClientError<AnyTRPCRouter> = error
              console.log({ appError })
              if (appError.data?.code === "UNAUTHORIZED") {
                if (appError.data?.cause instanceof SessionExpiredError) {
                  const loginUrl = login[lang]
                  window.location.assign(loginUrl)
                }
              }
            }
          },
        }),
        defaultOptions: {
          queries: {
            staleTime: 3000,
            retry(failureCount, error) {
              if (error instanceof TRPCClientError) {
                const appError: TRPCClientError<AnyTRPCRouter> = error

                // Do not retry query requests that got UNAUTHORIZED error.
                // It won't make a difference sending the same request again.

                if (appError.data?.code) {
                  if (
                    [
                      "UNAUTHORIZED",
                      "INTERNAL_SERVER_ERROR",
                      "FORBIDDEN",
                    ].includes(appError.data.code)
                  ) {
                    return false
                  }
                }
              }

              // Retry all client requests that fail (and are not handled above)
              // at most 3 times.
              return failureCount < 3
            },
          },
        },
      })
  )
  const [trpcClient] = useState(() => initializeTrpcClient())
  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    </trpc.Provider>
  )
}
