import { ClientContext, Client, NestedClient } from '@orpc/client';
import { OperationType, OperationKeyOptions } from '@orpc/tanstack-query';
export { OperationKeyOptions as BuildKeyOptions, OperationType as KeyType, generateOperationKey as buildKey } from '@orpc/tanstack-query';
import { QueryKey, SkipToken, QueryObserverOptions, QueryFunctionContext, InfiniteQueryObserverOptions, MutationObserverOptions, InfiniteData } from '@tanstack/vue-query';
import { AnyFunction, MaybeOptionalOptions } from '@orpc/shared';
import { MaybeRef, MaybeRefOrGetter, ComputedRef, Ref } from 'vue';

interface GeneralUtils<TInput> {
    /**
     * Generate a query/mutation key for checking status, invalidate, set, get, etc.
     *
     * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/basic#query-mutation-key Tanstack Query/Mutation Key Docs}
     */
    key<UType extends OperationType>(options?: OperationKeyOptions<UType, TInput>): QueryKey;
}
declare function createGeneralUtils<TInput>(path: string[]): GeneralUtils<TInput>;

/**
 * Since `@tanstack/vue-query` is not exporting the type `MaybeRefDeep` we need to copy it from the source code.
 * https://github.com/TanStack/query/blob/7ff544e12e79388e513b1cd886aeb946f80f0153/packages/vue-query/src/types.ts#L19C1-L27C2
 */
type MaybeRefDeep<T> = MaybeRef<T extends AnyFunction ? T : T extends object ? {
    [Property in keyof T]: MaybeRefDeep<T[Property]>;
} : T>;
type QueryOptionsIn<TClientContext extends ClientContext, TInput, TOutput, TError, TSelectData> = (undefined extends TInput ? {
    input?: MaybeRefDeep<TInput | SkipToken>;
} : {
    input: MaybeRefDeep<TInput | SkipToken>;
}) & (Record<never, never> extends TClientContext ? {
    context?: MaybeRefDeep<TClientContext>;
} : {
    context: MaybeRefDeep<TClientContext>;
}) & {
    [P in keyof Omit<QueryObserverOptions<TOutput, TError, TSelectData, TOutput>, 'queryKey' | 'enabled'>]: MaybeRefDeep<QueryObserverOptions<TOutput, TError, TSelectData, TOutput>[P]>;
} & {
    enabled?: MaybeRefOrGetter<QueryObserverOptions<TOutput, TError, TSelectData, TOutput>['enabled']>;
    queryKey?: MaybeRefDeep<QueryObserverOptions<TOutput, TError, TSelectData, TOutput>['queryKey']>;
    shallow?: boolean;
};
interface QueryOptionsBase<TOutput, TError> {
    queryKey: ComputedRef<QueryKey>;
    queryFn(ctx: QueryFunctionContext): Promise<TOutput>;
    throwOnError?(error: TError): boolean;
    retryDelay?: (count: number, error: TError) => number;
    enabled: ComputedRef<boolean | undefined>;
}
type InfiniteOptionsIn<TClientContext extends ClientContext, TInput, TOutput, TError, TSelectData, TPageParam> = (Record<never, never> extends TClientContext ? {
    context?: MaybeRefDeep<TClientContext>;
} : {
    context: MaybeRefDeep<TClientContext>;
}) & {
    [Property in keyof Omit<InfiniteQueryObserverOptions<TOutput, TError, TSelectData, QueryKey, TPageParam>, 'queryKey' | 'enabled'>]: MaybeRefDeep<InfiniteQueryObserverOptions<TOutput, TError, TSelectData, QueryKey, TPageParam>[Property]>;
} & {
    input: MaybeRef<((pageParam: TPageParam) => MaybeRefDeep<TInput>) | SkipToken>;
    enabled?: MaybeRefOrGetter<InfiniteQueryObserverOptions<TOutput, TError, TSelectData, QueryKey, TPageParam>['enabled']>;
    queryKey?: MaybeRefDeep<InfiniteQueryObserverOptions<TOutput, TError, TSelectData, QueryKey, TPageParam>['queryKey']>;
    shallow?: boolean;
};
interface InfiniteOptionsBase<TOutput, TError, TPageParam> {
    queryKey: ComputedRef<QueryKey>;
    queryFn(ctx: QueryFunctionContext<QueryKey, TPageParam>): Promise<TOutput>;
    throwOnError?(error: TError): boolean;
    retryDelay?: (count: number, error: TError) => number;
    enabled: ComputedRef<boolean | undefined>;
}
type MutationOptionsIn<TClientContext extends ClientContext, TInput, TOutput, TError, TMutationContext> = (Record<never, never> extends TClientContext ? {
    context?: TClientContext;
} : {
    context: TClientContext;
}) & MutationOptions<TInput, TOutput, TError, TMutationContext>;
type MutationOptions<TInput, TOutput, TError, TMutationContext> = {
    [P in keyof MutationObserverOptions<TOutput, TError, TInput, TMutationContext>]: MaybeRefDeep<MutationObserverOptions<TOutput, TError, TInput, TMutationContext>[P]>;
} & {
    shallow?: MaybeRef<boolean>;
};

interface ProcedureUtils<TClientContext extends ClientContext, TInput, TOutput, TError> {
    /**
     * Calling corresponding procedure client
     *
     * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/basic#calling-procedure-clients Tanstack Calling Procedure Client Docs}
     */
    call: Client<TClientContext, TInput, TOutput, TError>;
    /**
     * Generate options used for useQuery/prefetchQuery/...
     *
     * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/basic#query-options-utility Tanstack Query Options Utility Docs}
     */
    queryOptions<U, USelectData = TOutput>(...rest: MaybeOptionalOptions<U & QueryOptionsIn<TClientContext, TInput, TOutput, TError, USelectData>>): NoInfer<U & Omit<QueryOptionsBase<TOutput, TError>, keyof U>>;
    /**
     * Generate options used for useInfiniteQuery/prefetchInfiniteQuery/...
     *
     * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/basic#infinite-query-options-utility Tanstack Infinite Query Options Utility Docs}
     */
    infiniteOptions<U, UPageParam, USelectData = InfiniteData<TOutput, UPageParam>>(options: U & InfiniteOptionsIn<TClientContext, TInput, TOutput, TError, USelectData, UPageParam>): NoInfer<U & Omit<InfiniteOptionsBase<TOutput, TError, UPageParam>, keyof U>>;
    /**
     * Generate options used for useMutation/...
     *
     * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/basic#mutation-options Tanstack Mutation Options Docs}
     */
    mutationOptions<UMutationContext>(...rest: MaybeOptionalOptions<MutationOptionsIn<TClientContext, TInput, TOutput, TError, UMutationContext>>): MutationOptions<TInput, TOutput, TError, UMutationContext>;
}
interface CreateProcedureUtilsOptions {
    path: string[];
}
declare function createProcedureUtils<TClientContext extends ClientContext, TInput, TOutput, TError>(client: Client<TClientContext, TInput, TOutput, TError>, options: CreateProcedureUtilsOptions): ProcedureUtils<TClientContext, TInput, TOutput, TError>;

type RouterUtils<T extends NestedClient<any>> = T extends Client<infer UClientContext, infer UInput, infer UOutput, infer UError> ? ProcedureUtils<UClientContext, UInput, UOutput, UError> & GeneralUtils<UInput> : {
    [K in keyof T]: T[K] extends NestedClient<any> ? RouterUtils<T[K]> : never;
} & GeneralUtils<unknown>;
interface CreateRouterUtilsOptions {
    path?: string[];
}
/**
 * Create a router utils from a client.
 *
 * @info Both client-side and server-side clients are supported.
 * @see {@link https://orpc.dev/docs/integrations/tanstack-query-old/vue Tanstack Query Vue Docs}
 */
declare function createRouterUtils<T extends NestedClient<any>>(client: T, options?: CreateRouterUtilsOptions): RouterUtils<T>;

type UnrefDeep<T> = T extends Ref<infer U> ? UnrefDeep<U> : T extends AnyFunction ? T : T extends object ? {
    [K in keyof T]: UnrefDeep<T[K]>;
} : T;
declare function unrefDeep<T>(value: T): UnrefDeep<T>;

export { createGeneralUtils, createRouterUtils as createORPCVueQueryUtils, createProcedureUtils, createRouterUtils, unrefDeep };
export type { CreateProcedureUtilsOptions, CreateRouterUtilsOptions, GeneralUtils, InfiniteOptionsBase, InfiniteOptionsIn, MaybeRefDeep, MutationOptions, MutationOptionsIn, ProcedureUtils, QueryOptionsBase, QueryOptionsIn, RouterUtils, UnrefDeep };
