import * as swr from 'swr';
import { SWRConfiguration, SWRResponse, MutatorCallback, MutatorOptions } from 'swr';
import * as openapi_fetch from 'openapi-fetch';
import { MaybeOptionalInit, FetchResponse, Client } from 'openapi-fetch';
import * as openapi_typescript_helpers from 'openapi-typescript-helpers';
import { PathsWithMethod, HttpMethod, MediaType, RequiredKeysOf } from 'openapi-typescript-helpers';
import * as swr_infinite from 'swr/infinite';
import { SWRInfiniteConfiguration, SWRInfiniteKeyLoader } from 'swr/infinite';
import { PartialDeep } from 'type-fest';

type MaybeRequired<T> = RequiredKeysOf<T> extends never ? T | undefined : T;
type TryKey<T, K extends PropertyKey> = T extends {
    [Key in K]?: unknown;
} ? T[K] : undefined;
/**
 * Provides specific types used within a given request
 */
type TypesForRequest<Paths extends Record<string | number, any>, Method extends Extract<HttpMethod, keyof Paths[keyof Paths]>, Path extends PathsWithMethod<Paths, Method>, Init = MaybeOptionalInit<Paths[Path], Method>, Params = Init extends {
    params?: unknown;
} ? Init["params"] : undefined, Res = FetchResponse<Paths[Path][Method], Init, MediaType>, Data = Extract<Res, {
    data: unknown;
}>["data"], Error = Extract<Res, {
    error: unknown;
}>["error"], PathParams = TryKey<Params, "path">, Query = TryKey<Params, "query">, Headers = TryKey<Params, "header">, Cookies = TryKey<Params, "cookie">, SWRConfig = SWRConfiguration<Data, Error>> = {
    Init: Init;
    Data: Data;
    Error: Error;
    Path: MaybeRequired<PathParams>;
    Query: MaybeRequired<Query>;
    Headers: MaybeRequired<Headers>;
    Cookies: Cookies;
    SWRConfig: SWRConfig;
    SWRResponse: SWRResponse<Data, Error, SWRConfig>;
};
/**
 * Provides specific types for GET requests
 *
 * Uses {@link TypesForRequest}
 */
type TypesForGetRequest<Paths extends Record<string | number, any>, Path extends PathsWithMethod<Paths, Extract<"get", keyof Paths[keyof Paths]>>> = TypesForRequest<Paths, Extract<"get", keyof Paths[keyof Paths]>, Path>;

/**
 * Produces a typed wrapper for [`useSWRImmutable`](https://swr.vercel.app/docs/revalidation.en-US#disable-automatic-revalidations).
 *
 * ```ts
 * import createClient from "openapi-fetch";
 * const client = createClient();
 *
 * const useImmutable = createImmutableHook(client, "<unique-key>");
 *
 * // Fetch the query
 * useImmutable("/pets");
 *
 * // Skip the query
 * useImmutable("/pets", null);
 *
 * // Fetch the query with parameters
 * useImmutable("/pets", {
 *   params: { query: { limit: 10 } }
 * });
 *
 * // Fetch the query with parameters and SWR configuration
 * useImmutable(
 *   "/pets",
 *   { params: { query: { limit: 10 } } },
 *   { errorRetryCount: 2 },
 * );
 *
 * // Fetch the query with no parameters and SWR configuration
 * useImmutable(
 *   "/pets",
 *   {},
 *   { errorRetryCount: 2 },
 * );
 * ```
 */
declare const createImmutableHook: <Paths extends {}, IMediaType extends openapi_typescript_helpers.MediaType, Prefix extends string, FetcherError = never>(client: openapi_fetch.Client<Paths, IMediaType>, prefix: Prefix) => <Path extends openapi_typescript_helpers.PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"]>(path: Path, ...[init, config]: openapi_typescript_helpers.RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]) => swr.SWRResponse<Data, Error, swr.SWRConfiguration<Data_1, Error_1, swr.Fetcher<Data_1, SWRKey>> | undefined>;

/**
 * Produces a typed wrapper for [`useSWRInfinite`](https://swr.vercel.app/docs/pagination#useswrinfinite).
 *
 * ```ts
 * import createClient from "openapi-fetch";
 * const client = createClient();
 *
 * const useInfinite = createInfiniteHook(client, "<unique-key>");
 *
 * useInfinite("/pets", (index, previousPage) => {
 *   if (previousPage && !previousPage.hasMore) {
 *     return null;
 *   }
 *
 *   return {
 *     params: {
 *       query: {
 *         limit: 10,
 *         offset: index * 10,
 *       },
 *     },
 *   };
 * });
 * ```
 */
declare function createInfiniteHook<Paths extends {}, IMediaType extends MediaType, Prefix extends string, FetcherError = never>(client: Client<Paths, IMediaType>, prefix: Prefix): <Path extends PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends SWRInfiniteConfiguration<Data, Error>>(path: Path, getInit: SWRInfiniteKeyLoader<Data, Init | null>, config?: Config) => swr_infinite.SWRInfiniteResponse<Data, Error>;

type CompareFn = (init: any, partialInit: any) => boolean;
/**
 * Produces a typed wrapper for [`useSWRConfig#mutate`](https://swr.vercel.app/docs/mutation).
 *
 * ```ts
 * import createClient from "openapi-fetch";
 * import { isMatch } from "lodash";
 *
 * const client = createClient();
 *
 * const useMutate = createMutateHook(client, "<unique-key>", isMatch);
 *
 * const mutate = useMutate();
 *
 * // Revalidate all keys matching this path
 * await mutate(["/pets"]);
 * await mutate(["/pets"], newData);
 * await mutate(["/pets"], undefined, { revalidate: true });
 *
 * // Revlidate all keys matching this path and this subset of options
 * await mutate(
 *   ["/pets", { query: { limit: 10 } }],
 *   newData,
 *   { revalidate: false }
 * );
 * ```
 */
declare function createMutateHook<Paths extends {}, IMediaType extends MediaType>(client: Client<Paths, IMediaType>, prefix: string, compare: CompareFn): () => <Path extends PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"]>([path, init]: [Path, PartialDeep<Init>?], data?: R["Data"] | Promise<R["Data"]> | MutatorCallback<R["Data"]>, opts?: boolean | MutatorOptions<R["Data"]>) => Promise<(R["Data"] | undefined)[]>;

/**
 * Produces a typed wrapper for [`useSWR`](https://swr.vercel.app/docs/api).
 *
 * ```ts
 * import createClient from "openapi-fetch";
 *
 * const client = createClient();
 *
 * const useQuery = createQueryHook(client, "<unique-key>");
 *
 * // Fetch the query
 * useQuery("/pets");
 *
 * // Skip the query
 * useQuery("/pets", null);
 *
 * // Fetch the query with parameters
 * useQuery("/pets", {
 *   params: { query: { limit: 10 } }
 * });
 *
 * // Fetch the query with parameters and SWR configuration
 * useQuery(
 *   "/pets",
 *   { params: { query: { limit: 10 } } },
 *   { errorRetryCount: 2 },
 * );
 *
 * // Fetch the query with no parameters and SWR configuration
 * useQuery(
 *   "/pets",
 *   {},
 *   { errorRetryCount: 2 },
 * );
 * ```
 */
declare const createQueryHook: <Paths extends {}, IMediaType extends openapi_typescript_helpers.MediaType, Prefix extends string, FetcherError = never>(client: openapi_fetch.Client<Paths, IMediaType>, prefix: Prefix) => <Path extends openapi_typescript_helpers.PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"]>(path: Path, ...[init, config]: openapi_typescript_helpers.RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]) => swr.SWRResponse<Data, Error, swr.SWRConfiguration<Data_1, Error_1, swr.Fetcher<Data_1, SWRKey>> | undefined>;

export { createImmutableHook, createInfiniteHook, createMutateHook, createQueryHook };
export type { CompareFn, TypesForGetRequest, TypesForRequest };
