import {
  MutationCache,
  QueryCache,
  QueryClient,
} from "@tanstack/react-query";
import { toast } from "sonner-native";
import { ApiError, logError, reportError, toUserMessage } from "@/lib/errors";
import { useAuthStore } from "@/stores/auth-store";

declare module "@tanstack/react-query" {
  interface Register {
    queryMeta: { toastOnError?: boolean };
    mutationMeta: { suppressToast?: boolean };
  }
}

function shouldRetryQuery(failureCount: number, err: unknown): boolean {
  if (err instanceof ApiError) {
    // Retry only on transient status codes; 4xx generally won't succeed on retry.
    if (err.status === 408 || err.status === 429) return failureCount < 2;
    if (err.status >= 400 && err.status < 500) return false;
  }
  return failureCount < 2;
}

// A 401 surfaced through react-query means the server rejected our bearer
// token. This is the *only* place that turns that into an auth state change —
// the apiClient is a dumb transport. Direct apiClient callers (signIn,
// restoreSession, signInToFirebase) handle their own 401s explicitly.
function handleUnauthorized(err: unknown): void {
  if (err instanceof ApiError && err.status === 401) {
    void useAuthStore.getState().invalidateSession();
  }
}

export function createQueryClient(): QueryClient {
  return new QueryClient({
    defaultOptions: {
      queries: {
        retry: shouldRetryQuery,
        refetchOnWindowFocus: false,
      },
      mutations: {
        // Mutations have side effects — never auto-retry.
        retry: 0,
      },
    },
    queryCache: new QueryCache({
      onError: (err, query) => {
        handleUnauthorized(err);
        logError(err, { scope: "query", queryKey: query.queryKey });
        if (query.meta?.toastOnError) {
          toast.error(toUserMessage(err));
        }
      },
    }),
    mutationCache: new MutationCache({
      onError: (err, _variables, _context, mutation) => {
        handleUnauthorized(err);
        reportError(err, {
          scope: "mutation",
          mutationKey: mutation.options.mutationKey,
        });
        if (mutation.meta?.suppressToast) return;
        toast.error(toUserMessage(err));
      },
    }),
  });
}
