/* istanbul ignore file -- @preserve */
// We're testing this through E2E-testing
import type {
  CreateReactUtils,
  DecorateRouterRecord,
  TRPCUseQueries,
  TRPCUseSuspenseQueries,
} from '@trpc/react-query/shared';
import {
  createReactDecoration,
  createReactQueryUtils,
  createRootHooks,
} from '@trpc/react-query/shared';
import type {
  AnyRouter,
  ProtectedIntersection,
} from '@trpc/server/unstable-core-do-not-import';
import { createFlatProxy } from '@trpc/server/unstable-core-do-not-import';
import type { NextPageContext } from 'next/types.js';
import { useMemo } from 'react';
import type { WithTRPCNoSSROptions, WithTRPCSSROptions } from './withTRPC';
import { withTRPC } from './withTRPC';

/**
 * @internal
 */
export interface CreateTRPCNextBase<
  TRouter extends AnyRouter,
  TSSRContext extends NextPageContext,
> {
  /**
   * @deprecated renamed to `useUtils` and will be removed in a future tRPC version
   *
   * @see https://trpc.io/docs/client/react/useUtils
   */
  useContext(): CreateReactUtils<TRouter, TSSRContext>;
  /**
   * @see https://trpc.io/docs/client/react/useUtils
   */
  useUtils(): CreateReactUtils<TRouter, TSSRContext>;
  /**
   * Wraps your `_app` with the tRPC providers.
   * @see https://trpc.io/docs/client/nextjs/pages-router/setup#moving-from-createtrpcnext
   */
  withTRPC: ReturnType<typeof withTRPC<TRouter, TSSRContext>>;
  /**
   * @see https://trpc.io/docs/client/react/useQueries
   */
  useQueries: TRPCUseQueries<TRouter>;
  /**
   * @see https://trpc.io/docs/client/react/suspense#usesuspensequeries
   */
  useSuspenseQueries: TRPCUseSuspenseQueries<TRouter>;
}

/**
 * @internal
 * @deprecated part of `createTRPCNext`, which is built on `@trpc/react-query`.
 */
export type CreateTRPCNext<
  TRouter extends AnyRouter,
  TSSRContext extends NextPageContext,
> = ProtectedIntersection<
  CreateTRPCNextBase<TRouter, TSSRContext>,
  DecorateRouterRecord<
    TRouter['_def']['_config']['$types'],
    TRouter['_def']['record']
  >
>;

/**
 * Creates typed React hooks and a `withTRPC` wrapper for a Next.js Pages Router app.
 *
 * @example
 * ```ts
 * export const trpc = createTRPCNext<AppRouter>({
 *   config() {
 *     return { links: [httpBatchLink({ url: '/api/trpc' })] };
 *   },
 * });
 * ```
 *
 * @deprecated built on `@trpc/react-query`, which only gets bug fixes. Use
 * `createTRPCContext` from `@trpc/tanstack-react-query` instead.
 * @see https://trpc.io/docs/client/nextjs/pages-router/setup#moving-from-createtrpcnext
 */
export function createTRPCNext<
  TRouter extends AnyRouter,
  TSSRContext extends NextPageContext = NextPageContext,
>(
  opts: WithTRPCNoSSROptions<TRouter> | WithTRPCSSROptions<TRouter>,
): CreateTRPCNext<TRouter, TSSRContext> {
  const hooks = createRootHooks<TRouter, TSSRContext>(opts);

  // TODO: maybe set TSSRContext to `never` when using `WithTRPCNoSSROptions`
  const _withTRPC = withTRPC(opts);

  const proxy = createReactDecoration(hooks) as DecorateRouterRecord<
    TRouter['_def']['_config']['$types'],
    TRouter['_def']['record']
  >;

  return createFlatProxy((key) => {
    if (key === 'useContext' || key === 'useUtils') {
      return () => {
        const context = hooks.useUtils();
        // create a stable reference of the utils context
        return useMemo(() => {
          return (createReactQueryUtils as any)(context);
        }, [context]);
      };
    }

    if (key === 'useQueries') {
      return hooks.useQueries;
    }

    if (key === 'useSuspenseQueries') {
      return hooks.useSuspenseQueries;
    }

    if (key === 'withTRPC') {
      return _withTRPC;
    }

    return proxy[key];
  });
}
