/**
 * Generated by orval v8.5.3 🍺
 * Do not edit manually.
 * Api
 * TeaBoy OS API specification
 * OpenAPI spec version: 0.1.0
 */
import { useMutation, useQuery } from "@tanstack/react-query";
import type {
  MutationFunction,
  QueryFunction,
  QueryKey,
  UseMutationOptions,
  UseMutationResult,
  UseQueryOptions,
  UseQueryResult,
} from "@tanstack/react-query";

import type {
  AdminStats,
  App,
  AppSettings,
  AuthUser,
  ConversationWithDetails,
  CreateAppBody,
  CreateConversationBody,
  CreateServiceBody,
  ErrorResponse,
  HealthStatus,
  HomeStats,
  LoginBody,
  MessageWithSender,
  Notification,
  RegisterBody,
  RequestUploadUrlBody,
  RequestUploadUrlResponse,
  SendMessageBody,
  Service,
  ServiceCategory,
  SuccessResponse,
  UpdateAppBody,
  UpdateAppSettingsBody,
  UpdateLanguageBody,
  UpdateMyAppOrderBody,
  UpdateServiceBody,
  UpdateUserBody,
  UserProfile,
} from "./api.schemas";

import { customFetch } from "../custom-fetch";
import type { ErrorType, BodyType } from "../custom-fetch";

type AwaitedInput<T> = PromiseLike<T> | T;

type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;

type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];

/**
 * @summary Health check
 */
export const getHealthCheckUrl = () => {
  return `/api/healthz`;
};

export const healthCheck = async (
  options?: RequestInit,
): Promise<HealthStatus> => {
  return customFetch<HealthStatus>(getHealthCheckUrl(), {
    ...options,
    method: "GET",
  });
};

export const getHealthCheckQueryKey = () => {
  return [`/api/healthz`] as const;
};

export const getHealthCheckQueryOptions = <
  TData = Awaited<ReturnType<typeof healthCheck>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof healthCheck>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getHealthCheckQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof healthCheck>>> = ({
    signal,
  }) => healthCheck({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof healthCheck>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type HealthCheckQueryResult = NonNullable<
  Awaited<ReturnType<typeof healthCheck>>
>;
export type HealthCheckQueryError = ErrorType<unknown>;

/**
 * @summary Health check
 */

export function useHealthCheck<
  TData = Awaited<ReturnType<typeof healthCheck>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof healthCheck>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getHealthCheckQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Register a new user
 */
export const getRegisterUrl = () => {
  return `/api/auth/register`;
};

export const register = async (
  registerBody: RegisterBody,
  options?: RequestInit,
): Promise<AuthUser> => {
  return customFetch<AuthUser>(getRegisterUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(registerBody),
  });
};

export const getRegisterMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof register>>,
    TError,
    { data: BodyType<RegisterBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof register>>,
  TError,
  { data: BodyType<RegisterBody> },
  TContext
> => {
  const mutationKey = ["register"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof register>>,
    { data: BodyType<RegisterBody> }
  > = (props) => {
    const { data } = props ?? {};

    return register(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type RegisterMutationResult = NonNullable<
  Awaited<ReturnType<typeof register>>
>;
export type RegisterMutationBody = BodyType<RegisterBody>;
export type RegisterMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Register a new user
 */
export const useRegister = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof register>>,
    TError,
    { data: BodyType<RegisterBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof register>>,
  TError,
  { data: BodyType<RegisterBody> },
  TContext
> => {
  return useMutation(getRegisterMutationOptions(options));
};

/**
 * @summary Login
 */
export const getLoginUrl = () => {
  return `/api/auth/login`;
};

export const login = async (
  loginBody: LoginBody,
  options?: RequestInit,
): Promise<AuthUser> => {
  return customFetch<AuthUser>(getLoginUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(loginBody),
  });
};

export const getLoginMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof login>>,
    TError,
    { data: BodyType<LoginBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof login>>,
  TError,
  { data: BodyType<LoginBody> },
  TContext
> => {
  const mutationKey = ["login"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof login>>,
    { data: BodyType<LoginBody> }
  > = (props) => {
    const { data } = props ?? {};

    return login(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type LoginMutationResult = NonNullable<
  Awaited<ReturnType<typeof login>>
>;
export type LoginMutationBody = BodyType<LoginBody>;
export type LoginMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Login
 */
export const useLogin = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof login>>,
    TError,
    { data: BodyType<LoginBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof login>>,
  TError,
  { data: BodyType<LoginBody> },
  TContext
> => {
  return useMutation(getLoginMutationOptions(options));
};

/**
 * @summary Logout
 */
export const getLogoutUrl = () => {
  return `/api/auth/logout`;
};

export const logout = async (
  options?: RequestInit,
): Promise<SuccessResponse> => {
  return customFetch<SuccessResponse>(getLogoutUrl(), {
    ...options,
    method: "POST",
  });
};

export const getLogoutMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof logout>>,
    TError,
    void,
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof logout>>,
  TError,
  void,
  TContext
> => {
  const mutationKey = ["logout"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof logout>>,
    void
  > = () => {
    return logout(requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type LogoutMutationResult = NonNullable<
  Awaited<ReturnType<typeof logout>>
>;

export type LogoutMutationError = ErrorType<unknown>;

/**
 * @summary Logout
 */
export const useLogout = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof logout>>,
    TError,
    void,
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof logout>>,
  TError,
  void,
  TContext
> => {
  return useMutation(getLogoutMutationOptions(options));
};

/**
 * @summary Get current user
 */
export const getGetMeUrl = () => {
  return `/api/auth/me`;
};

export const getMe = async (options?: RequestInit): Promise<AuthUser> => {
  return customFetch<AuthUser>(getGetMeUrl(), {
    ...options,
    method: "GET",
  });
};

export const getGetMeQueryKey = () => {
  return [`/api/auth/me`] as const;
};

export const getGetMeQueryOptions = <
  TData = Awaited<ReturnType<typeof getMe>>,
  TError = ErrorType<ErrorResponse>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof getMe>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetMeQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getMe>>> = ({
    signal,
  }) => getMe({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof getMe>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetMeQueryResult = NonNullable<Awaited<ReturnType<typeof getMe>>>;
export type GetMeQueryError = ErrorType<ErrorResponse>;

/**
 * @summary Get current user
 */

export function useGetMe<
  TData = Awaited<ReturnType<typeof getMe>>,
  TError = ErrorType<ErrorResponse>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof getMe>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetMeQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Update preferred language
 */
export const getUpdateLanguageUrl = () => {
  return `/api/auth/me/language`;
};

export const updateLanguage = async (
  updateLanguageBody: UpdateLanguageBody,
  options?: RequestInit,
): Promise<AuthUser> => {
  return customFetch<AuthUser>(getUpdateLanguageUrl(), {
    ...options,
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateLanguageBody),
  });
};

export const getUpdateLanguageMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateLanguage>>,
    TError,
    { data: BodyType<UpdateLanguageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateLanguage>>,
  TError,
  { data: BodyType<UpdateLanguageBody> },
  TContext
> => {
  const mutationKey = ["updateLanguage"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateLanguage>>,
    { data: BodyType<UpdateLanguageBody> }
  > = (props) => {
    const { data } = props ?? {};

    return updateLanguage(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateLanguageMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateLanguage>>
>;
export type UpdateLanguageMutationBody = BodyType<UpdateLanguageBody>;
export type UpdateLanguageMutationError = ErrorType<unknown>;

/**
 * @summary Update preferred language
 */
export const useUpdateLanguage = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateLanguage>>,
    TError,
    { data: BodyType<UpdateLanguageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateLanguage>>,
  TError,
  { data: BodyType<UpdateLanguageBody> },
  TContext
> => {
  return useMutation(getUpdateLanguageMutationOptions(options));
};

/**
 * @summary List all active apps
 */
export const getListAppsUrl = () => {
  return `/api/apps`;
};

export const listApps = async (options?: RequestInit): Promise<App[]> => {
  return customFetch<App[]>(getListAppsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListAppsQueryKey = () => {
  return [`/api/apps`] as const;
};

export const getListAppsQueryOptions = <
  TData = Awaited<ReturnType<typeof listApps>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof listApps>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListAppsQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof listApps>>> = ({
    signal,
  }) => listApps({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listApps>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListAppsQueryResult = NonNullable<
  Awaited<ReturnType<typeof listApps>>
>;
export type ListAppsQueryError = ErrorType<unknown>;

/**
 * @summary List all active apps
 */

export function useListApps<
  TData = Awaited<ReturnType<typeof listApps>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof listApps>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListAppsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Create a new app (admin)
 */
export const getCreateAppUrl = () => {
  return `/api/apps`;
};

export const createApp = async (
  createAppBody: CreateAppBody,
  options?: RequestInit,
): Promise<App> => {
  return customFetch<App>(getCreateAppUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createAppBody),
  });
};

export const getCreateAppMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createApp>>,
    TError,
    { data: BodyType<CreateAppBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createApp>>,
  TError,
  { data: BodyType<CreateAppBody> },
  TContext
> => {
  const mutationKey = ["createApp"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof createApp>>,
    { data: BodyType<CreateAppBody> }
  > = (props) => {
    const { data } = props ?? {};

    return createApp(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type CreateAppMutationResult = NonNullable<
  Awaited<ReturnType<typeof createApp>>
>;
export type CreateAppMutationBody = BodyType<CreateAppBody>;
export type CreateAppMutationError = ErrorType<unknown>;

/**
 * @summary Create a new app (admin)
 */
export const useCreateApp = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createApp>>,
    TError,
    { data: BodyType<CreateAppBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createApp>>,
  TError,
  { data: BodyType<CreateAppBody> },
  TContext
> => {
  return useMutation(getCreateAppMutationOptions(options));
};

/**
 * @summary Get app by ID
 */
export const getGetAppUrl = (id: number) => {
  return `/api/apps/${id}`;
};

export const getApp = async (
  id: number,
  options?: RequestInit,
): Promise<App> => {
  return customFetch<App>(getGetAppUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetAppQueryKey = (id: number) => {
  return [`/api/apps/${id}`] as const;
};

export const getGetAppQueryOptions = <
  TData = Awaited<ReturnType<typeof getApp>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<Awaited<ReturnType<typeof getApp>>, TError, TData>;
    request?: SecondParameter<typeof customFetch>;
  },
) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetAppQueryKey(id);

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getApp>>> = ({
    signal,
  }) => getApp(id, { signal, ...requestOptions });

  return {
    queryKey,
    queryFn,
    enabled: !!id,
    ...queryOptions,
  } as UseQueryOptions<Awaited<ReturnType<typeof getApp>>, TError, TData> & {
    queryKey: QueryKey;
  };
};

export type GetAppQueryResult = NonNullable<Awaited<ReturnType<typeof getApp>>>;
export type GetAppQueryError = ErrorType<unknown>;

/**
 * @summary Get app by ID
 */

export function useGetApp<
  TData = Awaited<ReturnType<typeof getApp>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<Awaited<ReturnType<typeof getApp>>, TError, TData>;
    request?: SecondParameter<typeof customFetch>;
  },
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetAppQueryOptions(id, options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Update app (admin)
 */
export const getUpdateAppUrl = (id: number) => {
  return `/api/apps/${id}`;
};

export const updateApp = async (
  id: number,
  updateAppBody: UpdateAppBody,
  options?: RequestInit,
): Promise<App> => {
  return customFetch<App>(getUpdateAppUrl(id), {
    ...options,
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateAppBody),
  });
};

export const getUpdateAppMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateApp>>,
    TError,
    { id: number; data: BodyType<UpdateAppBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateApp>>,
  TError,
  { id: number; data: BodyType<UpdateAppBody> },
  TContext
> => {
  const mutationKey = ["updateApp"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateApp>>,
    { id: number; data: BodyType<UpdateAppBody> }
  > = (props) => {
    const { id, data } = props ?? {};

    return updateApp(id, data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateAppMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateApp>>
>;
export type UpdateAppMutationBody = BodyType<UpdateAppBody>;
export type UpdateAppMutationError = ErrorType<unknown>;

/**
 * @summary Update app (admin)
 */
export const useUpdateApp = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateApp>>,
    TError,
    { id: number; data: BodyType<UpdateAppBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateApp>>,
  TError,
  { id: number; data: BodyType<UpdateAppBody> },
  TContext
> => {
  return useMutation(getUpdateAppMutationOptions(options));
};

/**
 * @summary Delete app (admin)
 */
export const getDeleteAppUrl = (id: number) => {
  return `/api/apps/${id}`;
};

export const deleteApp = async (
  id: number,
  options?: RequestInit,
): Promise<void> => {
  return customFetch<void>(getDeleteAppUrl(id), {
    ...options,
    method: "DELETE",
  });
};

export const getDeleteAppMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteApp>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof deleteApp>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["deleteApp"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof deleteApp>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return deleteApp(id, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type DeleteAppMutationResult = NonNullable<
  Awaited<ReturnType<typeof deleteApp>>
>;

export type DeleteAppMutationError = ErrorType<unknown>;

/**
 * @summary Delete app (admin)
 */
export const useDeleteApp = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteApp>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof deleteApp>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getDeleteAppMutationOptions(options));
};

/**
 * @summary Set the current user's preferred home apps order
 */
export const getUpdateMyAppOrderUrl = () => {
  return `/api/me/app-order`;
};

export const updateMyAppOrder = async (
  updateMyAppOrderBody: UpdateMyAppOrderBody,
  options?: RequestInit,
): Promise<App[]> => {
  return customFetch<App[]>(getUpdateMyAppOrderUrl(), {
    ...options,
    method: "PUT",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateMyAppOrderBody),
  });
};

export const getUpdateMyAppOrderMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateMyAppOrder>>,
    TError,
    { data: BodyType<UpdateMyAppOrderBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateMyAppOrder>>,
  TError,
  { data: BodyType<UpdateMyAppOrderBody> },
  TContext
> => {
  const mutationKey = ["updateMyAppOrder"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateMyAppOrder>>,
    { data: BodyType<UpdateMyAppOrderBody> }
  > = (props) => {
    const { data } = props ?? {};

    return updateMyAppOrder(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateMyAppOrderMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateMyAppOrder>>
>;
export type UpdateMyAppOrderMutationBody = BodyType<UpdateMyAppOrderBody>;
export type UpdateMyAppOrderMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Set the current user's preferred home apps order
 */
export const useUpdateMyAppOrder = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateMyAppOrder>>,
    TError,
    { data: BodyType<UpdateMyAppOrderBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateMyAppOrder>>,
  TError,
  { data: BodyType<UpdateMyAppOrderBody> },
  TContext
> => {
  return useMutation(getUpdateMyAppOrderMutationOptions(options));
};

/**
 * @summary Get application settings (public)
 */
export const getGetAppSettingsUrl = () => {
  return `/api/settings`;
};

export const getAppSettings = async (
  options?: RequestInit,
): Promise<AppSettings> => {
  return customFetch<AppSettings>(getGetAppSettingsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getGetAppSettingsQueryKey = () => {
  return [`/api/settings`] as const;
};

export const getGetAppSettingsQueryOptions = <
  TData = Awaited<ReturnType<typeof getAppSettings>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getAppSettings>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetAppSettingsQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getAppSettings>>> = ({
    signal,
  }) => getAppSettings({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof getAppSettings>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetAppSettingsQueryResult = NonNullable<
  Awaited<ReturnType<typeof getAppSettings>>
>;
export type GetAppSettingsQueryError = ErrorType<unknown>;

/**
 * @summary Get application settings (public)
 */

export function useGetAppSettings<
  TData = Awaited<ReturnType<typeof getAppSettings>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getAppSettings>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetAppSettingsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Update application settings (admin)
 */
export const getUpdateAppSettingsUrl = () => {
  return `/api/settings`;
};

export const updateAppSettings = async (
  updateAppSettingsBody: UpdateAppSettingsBody,
  options?: RequestInit,
): Promise<AppSettings> => {
  return customFetch<AppSettings>(getUpdateAppSettingsUrl(), {
    ...options,
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateAppSettingsBody),
  });
};

export const getUpdateAppSettingsMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateAppSettings>>,
    TError,
    { data: BodyType<UpdateAppSettingsBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateAppSettings>>,
  TError,
  { data: BodyType<UpdateAppSettingsBody> },
  TContext
> => {
  const mutationKey = ["updateAppSettings"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateAppSettings>>,
    { data: BodyType<UpdateAppSettingsBody> }
  > = (props) => {
    const { data } = props ?? {};

    return updateAppSettings(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateAppSettingsMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateAppSettings>>
>;
export type UpdateAppSettingsMutationBody = BodyType<UpdateAppSettingsBody>;
export type UpdateAppSettingsMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Update application settings (admin)
 */
export const useUpdateAppSettings = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateAppSettings>>,
    TError,
    { data: BodyType<UpdateAppSettingsBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateAppSettings>>,
  TError,
  { data: BodyType<UpdateAppSettingsBody> },
  TContext
> => {
  return useMutation(getUpdateAppSettingsMutationOptions(options));
};

/**
 * @summary Request a presigned URL for file upload
 */
export const getRequestUploadUrlUrl = () => {
  return `/api/storage/uploads/request-url`;
};

export const requestUploadUrl = async (
  requestUploadUrlBody: RequestUploadUrlBody,
  options?: RequestInit,
): Promise<RequestUploadUrlResponse> => {
  return customFetch<RequestUploadUrlResponse>(getRequestUploadUrlUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(requestUploadUrlBody),
  });
};

export const getRequestUploadUrlMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof requestUploadUrl>>,
    TError,
    { data: BodyType<RequestUploadUrlBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof requestUploadUrl>>,
  TError,
  { data: BodyType<RequestUploadUrlBody> },
  TContext
> => {
  const mutationKey = ["requestUploadUrl"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof requestUploadUrl>>,
    { data: BodyType<RequestUploadUrlBody> }
  > = (props) => {
    const { data } = props ?? {};

    return requestUploadUrl(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type RequestUploadUrlMutationResult = NonNullable<
  Awaited<ReturnType<typeof requestUploadUrl>>
>;
export type RequestUploadUrlMutationBody = BodyType<RequestUploadUrlBody>;
export type RequestUploadUrlMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Request a presigned URL for file upload
 */
export const useRequestUploadUrl = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof requestUploadUrl>>,
    TError,
    { data: BodyType<RequestUploadUrlBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof requestUploadUrl>>,
  TError,
  { data: BodyType<RequestUploadUrlBody> },
  TContext
> => {
  return useMutation(getRequestUploadUrlMutationOptions(options));
};

/**
 * @summary List all services
 */
export const getListServicesUrl = () => {
  return `/api/services`;
};

export const listServices = async (
  options?: RequestInit,
): Promise<Service[]> => {
  return customFetch<Service[]>(getListServicesUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListServicesQueryKey = () => {
  return [`/api/services`] as const;
};

export const getListServicesQueryOptions = <
  TData = Awaited<ReturnType<typeof listServices>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listServices>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListServicesQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof listServices>>> = ({
    signal,
  }) => listServices({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listServices>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListServicesQueryResult = NonNullable<
  Awaited<ReturnType<typeof listServices>>
>;
export type ListServicesQueryError = ErrorType<unknown>;

/**
 * @summary List all services
 */

export function useListServices<
  TData = Awaited<ReturnType<typeof listServices>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listServices>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListServicesQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Create a service (admin)
 */
export const getCreateServiceUrl = () => {
  return `/api/services`;
};

export const createService = async (
  createServiceBody: CreateServiceBody,
  options?: RequestInit,
): Promise<Service> => {
  return customFetch<Service>(getCreateServiceUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createServiceBody),
  });
};

export const getCreateServiceMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createService>>,
    TError,
    { data: BodyType<CreateServiceBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createService>>,
  TError,
  { data: BodyType<CreateServiceBody> },
  TContext
> => {
  const mutationKey = ["createService"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof createService>>,
    { data: BodyType<CreateServiceBody> }
  > = (props) => {
    const { data } = props ?? {};

    return createService(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type CreateServiceMutationResult = NonNullable<
  Awaited<ReturnType<typeof createService>>
>;
export type CreateServiceMutationBody = BodyType<CreateServiceBody>;
export type CreateServiceMutationError = ErrorType<unknown>;

/**
 * @summary Create a service (admin)
 */
export const useCreateService = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createService>>,
    TError,
    { data: BodyType<CreateServiceBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createService>>,
  TError,
  { data: BodyType<CreateServiceBody> },
  TContext
> => {
  return useMutation(getCreateServiceMutationOptions(options));
};

/**
 * @summary Get service by ID
 */
export const getGetServiceUrl = (id: number) => {
  return `/api/services/${id}`;
};

export const getService = async (
  id: number,
  options?: RequestInit,
): Promise<Service> => {
  return customFetch<Service>(getGetServiceUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetServiceQueryKey = (id: number) => {
  return [`/api/services/${id}`] as const;
};

export const getGetServiceQueryOptions = <
  TData = Awaited<ReturnType<typeof getService>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof getService>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetServiceQueryKey(id);

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getService>>> = ({
    signal,
  }) => getService(id, { signal, ...requestOptions });

  return {
    queryKey,
    queryFn,
    enabled: !!id,
    ...queryOptions,
  } as UseQueryOptions<
    Awaited<ReturnType<typeof getService>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetServiceQueryResult = NonNullable<
  Awaited<ReturnType<typeof getService>>
>;
export type GetServiceQueryError = ErrorType<unknown>;

/**
 * @summary Get service by ID
 */

export function useGetService<
  TData = Awaited<ReturnType<typeof getService>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof getService>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetServiceQueryOptions(id, options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Update service (admin)
 */
export const getUpdateServiceUrl = (id: number) => {
  return `/api/services/${id}`;
};

export const updateService = async (
  id: number,
  updateServiceBody: UpdateServiceBody,
  options?: RequestInit,
): Promise<Service> => {
  return customFetch<Service>(getUpdateServiceUrl(id), {
    ...options,
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateServiceBody),
  });
};

export const getUpdateServiceMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateService>>,
    TError,
    { id: number; data: BodyType<UpdateServiceBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateService>>,
  TError,
  { id: number; data: BodyType<UpdateServiceBody> },
  TContext
> => {
  const mutationKey = ["updateService"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateService>>,
    { id: number; data: BodyType<UpdateServiceBody> }
  > = (props) => {
    const { id, data } = props ?? {};

    return updateService(id, data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateServiceMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateService>>
>;
export type UpdateServiceMutationBody = BodyType<UpdateServiceBody>;
export type UpdateServiceMutationError = ErrorType<unknown>;

/**
 * @summary Update service (admin)
 */
export const useUpdateService = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateService>>,
    TError,
    { id: number; data: BodyType<UpdateServiceBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateService>>,
  TError,
  { id: number; data: BodyType<UpdateServiceBody> },
  TContext
> => {
  return useMutation(getUpdateServiceMutationOptions(options));
};

/**
 * @summary Delete service (admin)
 */
export const getDeleteServiceUrl = (id: number) => {
  return `/api/services/${id}`;
};

export const deleteService = async (
  id: number,
  options?: RequestInit,
): Promise<void> => {
  return customFetch<void>(getDeleteServiceUrl(id), {
    ...options,
    method: "DELETE",
  });
};

export const getDeleteServiceMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteService>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof deleteService>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["deleteService"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof deleteService>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return deleteService(id, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type DeleteServiceMutationResult = NonNullable<
  Awaited<ReturnType<typeof deleteService>>
>;

export type DeleteServiceMutationError = ErrorType<unknown>;

/**
 * @summary Delete service (admin)
 */
export const useDeleteService = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteService>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof deleteService>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getDeleteServiceMutationOptions(options));
};

/**
 * @summary List service categories
 */
export const getListServiceCategoriesUrl = () => {
  return `/api/service-categories`;
};

export const listServiceCategories = async (
  options?: RequestInit,
): Promise<ServiceCategory[]> => {
  return customFetch<ServiceCategory[]>(getListServiceCategoriesUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListServiceCategoriesQueryKey = () => {
  return [`/api/service-categories`] as const;
};

export const getListServiceCategoriesQueryOptions = <
  TData = Awaited<ReturnType<typeof listServiceCategories>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listServiceCategories>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListServiceCategoriesQueryKey();

  const queryFn: QueryFunction<
    Awaited<ReturnType<typeof listServiceCategories>>
  > = ({ signal }) => listServiceCategories({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listServiceCategories>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListServiceCategoriesQueryResult = NonNullable<
  Awaited<ReturnType<typeof listServiceCategories>>
>;
export type ListServiceCategoriesQueryError = ErrorType<unknown>;

/**
 * @summary List service categories
 */

export function useListServiceCategories<
  TData = Awaited<ReturnType<typeof listServiceCategories>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listServiceCategories>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListServiceCategoriesQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary List conversations for current user
 */
export const getListConversationsUrl = () => {
  return `/api/conversations`;
};

export const listConversations = async (
  options?: RequestInit,
): Promise<ConversationWithDetails[]> => {
  return customFetch<ConversationWithDetails[]>(getListConversationsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListConversationsQueryKey = () => {
  return [`/api/conversations`] as const;
};

export const getListConversationsQueryOptions = <
  TData = Awaited<ReturnType<typeof listConversations>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listConversations>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListConversationsQueryKey();

  const queryFn: QueryFunction<
    Awaited<ReturnType<typeof listConversations>>
  > = ({ signal }) => listConversations({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listConversations>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListConversationsQueryResult = NonNullable<
  Awaited<ReturnType<typeof listConversations>>
>;
export type ListConversationsQueryError = ErrorType<unknown>;

/**
 * @summary List conversations for current user
 */

export function useListConversations<
  TData = Awaited<ReturnType<typeof listConversations>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listConversations>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListConversationsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Create a conversation
 */
export const getCreateConversationUrl = () => {
  return `/api/conversations`;
};

export const createConversation = async (
  createConversationBody: CreateConversationBody,
  options?: RequestInit,
): Promise<ConversationWithDetails> => {
  return customFetch<ConversationWithDetails>(getCreateConversationUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createConversationBody),
  });
};

export const getCreateConversationMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createConversation>>,
    TError,
    { data: BodyType<CreateConversationBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createConversation>>,
  TError,
  { data: BodyType<CreateConversationBody> },
  TContext
> => {
  const mutationKey = ["createConversation"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof createConversation>>,
    { data: BodyType<CreateConversationBody> }
  > = (props) => {
    const { data } = props ?? {};

    return createConversation(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type CreateConversationMutationResult = NonNullable<
  Awaited<ReturnType<typeof createConversation>>
>;
export type CreateConversationMutationBody = BodyType<CreateConversationBody>;
export type CreateConversationMutationError = ErrorType<unknown>;

/**
 * @summary Create a conversation
 */
export const useCreateConversation = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createConversation>>,
    TError,
    { data: BodyType<CreateConversationBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createConversation>>,
  TError,
  { data: BodyType<CreateConversationBody> },
  TContext
> => {
  return useMutation(getCreateConversationMutationOptions(options));
};

/**
 * @summary Get conversation by ID
 */
export const getGetConversationUrl = (id: number) => {
  return `/api/conversations/${id}`;
};

export const getConversation = async (
  id: number,
  options?: RequestInit,
): Promise<ConversationWithDetails> => {
  return customFetch<ConversationWithDetails>(getGetConversationUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetConversationQueryKey = (id: number) => {
  return [`/api/conversations/${id}`] as const;
};

export const getGetConversationQueryOptions = <
  TData = Awaited<ReturnType<typeof getConversation>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof getConversation>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetConversationQueryKey(id);

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getConversation>>> = ({
    signal,
  }) => getConversation(id, { signal, ...requestOptions });

  return {
    queryKey,
    queryFn,
    enabled: !!id,
    ...queryOptions,
  } as UseQueryOptions<
    Awaited<ReturnType<typeof getConversation>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetConversationQueryResult = NonNullable<
  Awaited<ReturnType<typeof getConversation>>
>;
export type GetConversationQueryError = ErrorType<unknown>;

/**
 * @summary Get conversation by ID
 */

export function useGetConversation<
  TData = Awaited<ReturnType<typeof getConversation>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof getConversation>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetConversationQueryOptions(id, options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary List messages in a conversation
 */
export const getListMessagesUrl = (id: number) => {
  return `/api/conversations/${id}/messages`;
};

export const listMessages = async (
  id: number,
  options?: RequestInit,
): Promise<MessageWithSender[]> => {
  return customFetch<MessageWithSender[]>(getListMessagesUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getListMessagesQueryKey = (id: number) => {
  return [`/api/conversations/${id}/messages`] as const;
};

export const getListMessagesQueryOptions = <
  TData = Awaited<ReturnType<typeof listMessages>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof listMessages>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListMessagesQueryKey(id);

  const queryFn: QueryFunction<Awaited<ReturnType<typeof listMessages>>> = ({
    signal,
  }) => listMessages(id, { signal, ...requestOptions });

  return {
    queryKey,
    queryFn,
    enabled: !!id,
    ...queryOptions,
  } as UseQueryOptions<
    Awaited<ReturnType<typeof listMessages>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListMessagesQueryResult = NonNullable<
  Awaited<ReturnType<typeof listMessages>>
>;
export type ListMessagesQueryError = ErrorType<unknown>;

/**
 * @summary List messages in a conversation
 */

export function useListMessages<
  TData = Awaited<ReturnType<typeof listMessages>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<
      Awaited<ReturnType<typeof listMessages>>,
      TError,
      TData
    >;
    request?: SecondParameter<typeof customFetch>;
  },
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListMessagesQueryOptions(id, options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Send a message
 */
export const getSendMessageUrl = (id: number) => {
  return `/api/conversations/${id}/messages`;
};

export const sendMessage = async (
  id: number,
  sendMessageBody: SendMessageBody,
  options?: RequestInit,
): Promise<MessageWithSender> => {
  return customFetch<MessageWithSender>(getSendMessageUrl(id), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(sendMessageBody),
  });
};

export const getSendMessageMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof sendMessage>>,
    TError,
    { id: number; data: BodyType<SendMessageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof sendMessage>>,
  TError,
  { id: number; data: BodyType<SendMessageBody> },
  TContext
> => {
  const mutationKey = ["sendMessage"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof sendMessage>>,
    { id: number; data: BodyType<SendMessageBody> }
  > = (props) => {
    const { id, data } = props ?? {};

    return sendMessage(id, data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type SendMessageMutationResult = NonNullable<
  Awaited<ReturnType<typeof sendMessage>>
>;
export type SendMessageMutationBody = BodyType<SendMessageBody>;
export type SendMessageMutationError = ErrorType<unknown>;

/**
 * @summary Send a message
 */
export const useSendMessage = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof sendMessage>>,
    TError,
    { id: number; data: BodyType<SendMessageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof sendMessage>>,
  TError,
  { id: number; data: BodyType<SendMessageBody> },
  TContext
> => {
  return useMutation(getSendMessageMutationOptions(options));
};

/**
 * @summary Mark all messages in conversation as read
 */
export const getMarkConversationReadUrl = (id: number) => {
  return `/api/conversations/${id}/read`;
};

export const markConversationRead = async (
  id: number,
  options?: RequestInit,
): Promise<SuccessResponse> => {
  return customFetch<SuccessResponse>(getMarkConversationReadUrl(id), {
    ...options,
    method: "POST",
  });
};

export const getMarkConversationReadMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markConversationRead>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof markConversationRead>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["markConversationRead"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof markConversationRead>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return markConversationRead(id, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type MarkConversationReadMutationResult = NonNullable<
  Awaited<ReturnType<typeof markConversationRead>>
>;

export type MarkConversationReadMutationError = ErrorType<unknown>;

/**
 * @summary Mark all messages in conversation as read
 */
export const useMarkConversationRead = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markConversationRead>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof markConversationRead>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getMarkConversationReadMutationOptions(options));
};

/**
 * @summary List notifications for current user
 */
export const getListNotificationsUrl = () => {
  return `/api/notifications`;
};

export const listNotifications = async (
  options?: RequestInit,
): Promise<Notification[]> => {
  return customFetch<Notification[]>(getListNotificationsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListNotificationsQueryKey = () => {
  return [`/api/notifications`] as const;
};

export const getListNotificationsQueryOptions = <
  TData = Awaited<ReturnType<typeof listNotifications>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listNotifications>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListNotificationsQueryKey();

  const queryFn: QueryFunction<
    Awaited<ReturnType<typeof listNotifications>>
  > = ({ signal }) => listNotifications({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listNotifications>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListNotificationsQueryResult = NonNullable<
  Awaited<ReturnType<typeof listNotifications>>
>;
export type ListNotificationsQueryError = ErrorType<unknown>;

/**
 * @summary List notifications for current user
 */

export function useListNotifications<
  TData = Awaited<ReturnType<typeof listNotifications>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof listNotifications>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListNotificationsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Mark notification as read
 */
export const getMarkNotificationReadUrl = (id: number) => {
  return `/api/notifications/${id}/read`;
};

export const markNotificationRead = async (
  id: number,
  options?: RequestInit,
): Promise<Notification> => {
  return customFetch<Notification>(getMarkNotificationReadUrl(id), {
    ...options,
    method: "PATCH",
  });
};

export const getMarkNotificationReadMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markNotificationRead>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof markNotificationRead>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["markNotificationRead"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof markNotificationRead>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return markNotificationRead(id, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type MarkNotificationReadMutationResult = NonNullable<
  Awaited<ReturnType<typeof markNotificationRead>>
>;

export type MarkNotificationReadMutationError = ErrorType<unknown>;

/**
 * @summary Mark notification as read
 */
export const useMarkNotificationRead = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markNotificationRead>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof markNotificationRead>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getMarkNotificationReadMutationOptions(options));
};

/**
 * @summary Mark all notifications as read
 */
export const getMarkAllNotificationsReadUrl = () => {
  return `/api/notifications/read-all`;
};

export const markAllNotificationsRead = async (
  options?: RequestInit,
): Promise<SuccessResponse> => {
  return customFetch<SuccessResponse>(getMarkAllNotificationsReadUrl(), {
    ...options,
    method: "POST",
  });
};

export const getMarkAllNotificationsReadMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markAllNotificationsRead>>,
    TError,
    void,
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof markAllNotificationsRead>>,
  TError,
  void,
  TContext
> => {
  const mutationKey = ["markAllNotificationsRead"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof markAllNotificationsRead>>,
    void
  > = () => {
    return markAllNotificationsRead(requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type MarkAllNotificationsReadMutationResult = NonNullable<
  Awaited<ReturnType<typeof markAllNotificationsRead>>
>;

export type MarkAllNotificationsReadMutationError = ErrorType<unknown>;

/**
 * @summary Mark all notifications as read
 */
export const useMarkAllNotificationsRead = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof markAllNotificationsRead>>,
    TError,
    void,
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof markAllNotificationsRead>>,
  TError,
  void,
  TContext
> => {
  return useMutation(getMarkAllNotificationsReadMutationOptions(options));
};

/**
 * @summary List all users (admin)
 */
export const getListUsersUrl = () => {
  return `/api/users`;
};

export const listUsers = async (
  options?: RequestInit,
): Promise<UserProfile[]> => {
  return customFetch<UserProfile[]>(getListUsersUrl(), {
    ...options,
    method: "GET",
  });
};

export const getListUsersQueryKey = () => {
  return [`/api/users`] as const;
};

export const getListUsersQueryOptions = <
  TData = Awaited<ReturnType<typeof listUsers>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof listUsers>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getListUsersQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof listUsers>>> = ({
    signal,
  }) => listUsers({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof listUsers>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type ListUsersQueryResult = NonNullable<
  Awaited<ReturnType<typeof listUsers>>
>;
export type ListUsersQueryError = ErrorType<unknown>;

/**
 * @summary List all users (admin)
 */

export function useListUsers<
  TData = Awaited<ReturnType<typeof listUsers>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<Awaited<ReturnType<typeof listUsers>>, TError, TData>;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getListUsersQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Create a user (admin)
 */
export const getCreateUserUrl = () => {
  return `/api/users`;
};

export const createUser = async (
  registerBody: RegisterBody,
  options?: RequestInit,
): Promise<UserProfile> => {
  return customFetch<UserProfile>(getCreateUserUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(registerBody),
  });
};

export const getCreateUserMutationOptions = <
  TError = ErrorType<void>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createUser>>,
    TError,
    { data: BodyType<RegisterBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createUser>>,
  TError,
  { data: BodyType<RegisterBody> },
  TContext
> => {
  const mutationKey = ["createUser"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof createUser>>,
    { data: BodyType<RegisterBody> }
  > = (props) => {
    const { data } = props ?? {};

    return createUser(data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type CreateUserMutationResult = NonNullable<
  Awaited<ReturnType<typeof createUser>>
>;
export type CreateUserMutationBody = BodyType<RegisterBody>;
export type CreateUserMutationError = ErrorType<void>;

/**
 * @summary Create a user (admin)
 */
export const useCreateUser = <
  TError = ErrorType<void>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createUser>>,
    TError,
    { data: BodyType<RegisterBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createUser>>,
  TError,
  { data: BodyType<RegisterBody> },
  TContext
> => {
  return useMutation(getCreateUserMutationOptions(options));
};

/**
 * @summary Get user by ID (admin)
 */
export const getGetUserUrl = (id: number) => {
  return `/api/users/${id}`;
};

export const getUser = async (
  id: number,
  options?: RequestInit,
): Promise<UserProfile> => {
  return customFetch<UserProfile>(getGetUserUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetUserQueryKey = (id: number) => {
  return [`/api/users/${id}`] as const;
};

export const getGetUserQueryOptions = <
  TData = Awaited<ReturnType<typeof getUser>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<Awaited<ReturnType<typeof getUser>>, TError, TData>;
    request?: SecondParameter<typeof customFetch>;
  },
) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetUserQueryKey(id);

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getUser>>> = ({
    signal,
  }) => getUser(id, { signal, ...requestOptions });

  return {
    queryKey,
    queryFn,
    enabled: !!id,
    ...queryOptions,
  } as UseQueryOptions<Awaited<ReturnType<typeof getUser>>, TError, TData> & {
    queryKey: QueryKey;
  };
};

export type GetUserQueryResult = NonNullable<
  Awaited<ReturnType<typeof getUser>>
>;
export type GetUserQueryError = ErrorType<unknown>;

/**
 * @summary Get user by ID (admin)
 */

export function useGetUser<
  TData = Awaited<ReturnType<typeof getUser>>,
  TError = ErrorType<unknown>,
>(
  id: number,
  options?: {
    query?: UseQueryOptions<Awaited<ReturnType<typeof getUser>>, TError, TData>;
    request?: SecondParameter<typeof customFetch>;
  },
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetUserQueryOptions(id, options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Update user (admin)
 */
export const getUpdateUserUrl = (id: number) => {
  return `/api/users/${id}`;
};

export const updateUser = async (
  id: number,
  updateUserBody: UpdateUserBody,
  options?: RequestInit,
): Promise<UserProfile> => {
  return customFetch<UserProfile>(getUpdateUserUrl(id), {
    ...options,
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(updateUserBody),
  });
};

export const getUpdateUserMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateUser>>,
    TError,
    { id: number; data: BodyType<UpdateUserBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof updateUser>>,
  TError,
  { id: number; data: BodyType<UpdateUserBody> },
  TContext
> => {
  const mutationKey = ["updateUser"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof updateUser>>,
    { id: number; data: BodyType<UpdateUserBody> }
  > = (props) => {
    const { id, data } = props ?? {};

    return updateUser(id, data, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type UpdateUserMutationResult = NonNullable<
  Awaited<ReturnType<typeof updateUser>>
>;
export type UpdateUserMutationBody = BodyType<UpdateUserBody>;
export type UpdateUserMutationError = ErrorType<unknown>;

/**
 * @summary Update user (admin)
 */
export const useUpdateUser = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof updateUser>>,
    TError,
    { id: number; data: BodyType<UpdateUserBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof updateUser>>,
  TError,
  { id: number; data: BodyType<UpdateUserBody> },
  TContext
> => {
  return useMutation(getUpdateUserMutationOptions(options));
};

/**
 * @summary Delete user (admin)
 */
export const getDeleteUserUrl = (id: number) => {
  return `/api/users/${id}`;
};

export const deleteUser = async (
  id: number,
  options?: RequestInit,
): Promise<void> => {
  return customFetch<void>(getDeleteUserUrl(id), {
    ...options,
    method: "DELETE",
  });
};

export const getDeleteUserMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteUser>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof deleteUser>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["deleteUser"];
  const { mutation: mutationOptions, request: requestOptions } = options
    ? options.mutation &&
      "mutationKey" in options.mutation &&
      options.mutation.mutationKey
      ? options
      : { ...options, mutation: { ...options.mutation, mutationKey } }
    : { mutation: { mutationKey }, request: undefined };

  const mutationFn: MutationFunction<
    Awaited<ReturnType<typeof deleteUser>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return deleteUser(id, requestOptions);
  };

  return { mutationFn, ...mutationOptions };
};

export type DeleteUserMutationResult = NonNullable<
  Awaited<ReturnType<typeof deleteUser>>
>;

export type DeleteUserMutationError = ErrorType<unknown>;

/**
 * @summary Delete user (admin)
 */
export const useDeleteUser = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteUser>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof deleteUser>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getDeleteUserMutationOptions(options));
};

/**
 * @summary Get home screen stats
 */
export const getGetHomeStatsUrl = () => {
  return `/api/stats/home`;
};

export const getHomeStats = async (
  options?: RequestInit,
): Promise<HomeStats> => {
  return customFetch<HomeStats>(getGetHomeStatsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getGetHomeStatsQueryKey = () => {
  return [`/api/stats/home`] as const;
};

export const getGetHomeStatsQueryOptions = <
  TData = Awaited<ReturnType<typeof getHomeStats>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getHomeStats>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetHomeStatsQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getHomeStats>>> = ({
    signal,
  }) => getHomeStats({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof getHomeStats>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetHomeStatsQueryResult = NonNullable<
  Awaited<ReturnType<typeof getHomeStats>>
>;
export type GetHomeStatsQueryError = ErrorType<unknown>;

/**
 * @summary Get home screen stats
 */

export function useGetHomeStats<
  TData = Awaited<ReturnType<typeof getHomeStats>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getHomeStats>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetHomeStatsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}

/**
 * @summary Get admin dashboard trend stats
 */
export const getGetAdminStatsUrl = () => {
  return `/api/stats/admin`;
};

export const getAdminStats = async (
  options?: RequestInit,
): Promise<AdminStats> => {
  return customFetch<AdminStats>(getGetAdminStatsUrl(), {
    ...options,
    method: "GET",
  });
};

export const getGetAdminStatsQueryKey = () => {
  return [`/api/stats/admin`] as const;
};

export const getGetAdminStatsQueryOptions = <
  TData = Awaited<ReturnType<typeof getAdminStats>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getAdminStats>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}) => {
  const { query: queryOptions, request: requestOptions } = options ?? {};

  const queryKey = queryOptions?.queryKey ?? getGetAdminStatsQueryKey();

  const queryFn: QueryFunction<Awaited<ReturnType<typeof getAdminStats>>> = ({
    signal,
  }) => getAdminStats({ signal, ...requestOptions });

  return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
    Awaited<ReturnType<typeof getAdminStats>>,
    TError,
    TData
  > & { queryKey: QueryKey };
};

export type GetAdminStatsQueryResult = NonNullable<
  Awaited<ReturnType<typeof getAdminStats>>
>;
export type GetAdminStatsQueryError = ErrorType<unknown>;

/**
 * @summary Get admin dashboard trend stats
 */

export function useGetAdminStats<
  TData = Awaited<ReturnType<typeof getAdminStats>>,
  TError = ErrorType<unknown>,
>(options?: {
  query?: UseQueryOptions<
    Awaited<ReturnType<typeof getAdminStats>>,
    TError,
    TData
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
  const queryOptions = getGetAdminStatsQueryOptions(options);

  const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
    queryKey: QueryKey;
  };

  return { ...query, queryKey: queryOptions.queryKey };
}
