/**
 * Generated by orval v8.5.3 🍺
 * Do not edit manually.
 * Api
 * 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 {
  ClaimRefundRequest,
  ClaimRefundResponse,
  CreateGeminiConversationBody,
  CreateJobRequest,
  CreateJobResponse,
  CreateSessionRequest,
  CreateSessionResponse,
  DemoResponse,
  ErrorResponse,
  GeminiConversation,
  GeminiConversationWithMessages,
  GeminiError,
  GeminiMessage,
  GenerateGeminiImageBody,
  GenerateGeminiImageResponse,
  HealthStatus,
  JobStatusResponse,
  RunDemoParams,
  SendGeminiMessageBody,
  SessionRequestBody,
  SessionRequestResponse,
  SessionStatusResponse,
  TopupSessionResponse,
} 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];

/**
 * Returns server health status
 * @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 };
}

/**
 * Accepts a request, creates a job row, and issues an eval fee Lightning invoice.
 * @summary Create a new agent job
 */
export const getCreateJobUrl = () => {
  return `/api/jobs`;
};

export const createJob = async (
  createJobRequest: CreateJobRequest,
  options?: RequestInit,
): Promise<CreateJobResponse> => {
  return customFetch<CreateJobResponse>(getCreateJobUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createJobRequest),
  });
};

export const getCreateJobMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createJob>>,
    TError,
    { data: BodyType<CreateJobRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createJob>>,
  TError,
  { data: BodyType<CreateJobRequest> },
  TContext
> => {
  const mutationKey = ["createJob"];
  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 createJob>>,
    { data: BodyType<CreateJobRequest> }
  > = (props) => {
    const { data } = props ?? {};

    return createJob(data, requestOptions);
  };

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

export type CreateJobMutationResult = NonNullable<
  Awaited<ReturnType<typeof createJob>>
>;
export type CreateJobMutationBody = BodyType<CreateJobRequest>;
export type CreateJobMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Create a new agent job
 */
export const useCreateJob = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createJob>>,
    TError,
    { data: BodyType<CreateJobRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createJob>>,
  TError,
  { data: BodyType<CreateJobRequest> },
  TContext
> => {
  return useMutation(getCreateJobMutationOptions(options));
};

/**
 * Returns current job state. Automatically advances the state machine when a pending invoice is found to be paid.
 * @summary Get job status
 */
export const getGetJobUrl = (id: string) => {
  return `/api/jobs/${id}`;
};

export const getJob = async (
  id: string,
  options?: RequestInit,
): Promise<JobStatusResponse> => {
  return customFetch<JobStatusResponse>(getGetJobUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetJobQueryKey = (id: string) => {
  return [`/api/jobs/${id}`] as const;
};

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

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

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

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

export type GetJobQueryResult = NonNullable<Awaited<ReturnType<typeof getJob>>>;
export type GetJobQueryError = ErrorType<ErrorResponse>;

/**
 * @summary Get job status
 */

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

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

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

/**
 * After a job completes, if the actual cost (tokens used + infra + margin) was
less than the work invoice amount, the difference is owed back to the user.
Submit a BOLT11 invoice for exactly `refundAmountSats` to receive the payment.
Idempotent: returns 409 if already paid or if no refund is owed.

 * @summary Claim a refund for overpayment
 */
export const getClaimRefundUrl = (id: string) => {
  return `/api/jobs/${id}/refund`;
};

export const claimRefund = async (
  id: string,
  claimRefundRequest: ClaimRefundRequest,
  options?: RequestInit,
): Promise<ClaimRefundResponse> => {
  return customFetch<ClaimRefundResponse>(getClaimRefundUrl(id), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(claimRefundRequest),
  });
};

export const getClaimRefundMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof claimRefund>>,
    TError,
    { id: string; data: BodyType<ClaimRefundRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof claimRefund>>,
  TError,
  { id: string; data: BodyType<ClaimRefundRequest> },
  TContext
> => {
  const mutationKey = ["claimRefund"];
  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 claimRefund>>,
    { id: string; data: BodyType<ClaimRefundRequest> }
  > = (props) => {
    const { id, data } = props ?? {};

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

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

export type ClaimRefundMutationResult = NonNullable<
  Awaited<ReturnType<typeof claimRefund>>
>;
export type ClaimRefundMutationBody = BodyType<ClaimRefundRequest>;
export type ClaimRefundMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Claim a refund for overpayment
 */
export const useClaimRefund = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof claimRefund>>,
    TError,
    { id: string; data: BodyType<ClaimRefundRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof claimRefund>>,
  TError,
  { id: string; data: BodyType<ClaimRefundRequest> },
  TContext
> => {
  return useMutation(getClaimRefundMutationOptions(options));
};

/**
 * Opens a new session. Pay the returned Lightning invoice to activate it.
Once active, use the `macaroon` from GET /sessions/:id to authenticate requests.
Deposits: 100–10,000 sats. Sessions expire after 24 h of inactivity.

 * @summary Create a pre-funded session
 */
export const getCreateSessionUrl = () => {
  return `/api/sessions`;
};

export const createSession = async (
  createSessionRequest: CreateSessionRequest,
  options?: RequestInit,
): Promise<CreateSessionResponse> => {
  return customFetch<CreateSessionResponse>(getCreateSessionUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createSessionRequest),
  });
};

export const getCreateSessionMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createSession>>,
    TError,
    { data: BodyType<CreateSessionRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createSession>>,
  TError,
  { data: BodyType<CreateSessionRequest> },
  TContext
> => {
  const mutationKey = ["createSession"];
  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 createSession>>,
    { data: BodyType<CreateSessionRequest> }
  > = (props) => {
    const { data } = props ?? {};

    return createSession(data, requestOptions);
  };

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

export type CreateSessionMutationResult = NonNullable<
  Awaited<ReturnType<typeof createSession>>
>;
export type CreateSessionMutationBody = BodyType<CreateSessionRequest>;
export type CreateSessionMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Create a pre-funded session
 */
export const useCreateSession = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createSession>>,
    TError,
    { data: BodyType<CreateSessionRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof createSession>>,
  TError,
  { data: BodyType<CreateSessionRequest> },
  TContext
> => {
  return useMutation(getCreateSessionMutationOptions(options));
};

/**
 * Returns current state, balance, and pending invoice info. Auto-advances on payment.
 * @summary Get session status
 */
export const getGetSessionUrl = (id: string) => {
  return `/api/sessions/${id}`;
};

export const getSession = async (
  id: string,
  options?: RequestInit,
): Promise<SessionStatusResponse> => {
  return customFetch<SessionStatusResponse>(getGetSessionUrl(id), {
    ...options,
    method: "GET",
  });
};

export const getGetSessionQueryKey = (id: string) => {
  return [`/api/sessions/${id}`] as const;
};

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

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

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

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

export type GetSessionQueryResult = NonNullable<
  Awaited<ReturnType<typeof getSession>>
>;
export type GetSessionQueryError = ErrorType<ErrorResponse>;

/**
 * @summary Get session status
 */

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

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

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

/**
 * Runs eval + work and debits the actual compute cost from the session balance.
Rejected requests still incur a small eval fee. Requires `Authorization: Bearer <macaroon>`.

 * @summary Submit a request against a session balance
 */
export const getSubmitSessionRequestUrl = (id: string) => {
  return `/api/sessions/${id}/request`;
};

export const submitSessionRequest = async (
  id: string,
  sessionRequestBody: SessionRequestBody,
  options?: RequestInit,
): Promise<SessionRequestResponse> => {
  return customFetch<SessionRequestResponse>(getSubmitSessionRequestUrl(id), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(sessionRequestBody),
  });
};

export const getSubmitSessionRequestMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof submitSessionRequest>>,
    TError,
    { id: string; data: BodyType<SessionRequestBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof submitSessionRequest>>,
  TError,
  { id: string; data: BodyType<SessionRequestBody> },
  TContext
> => {
  const mutationKey = ["submitSessionRequest"];
  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 submitSessionRequest>>,
    { id: string; data: BodyType<SessionRequestBody> }
  > = (props) => {
    const { id, data } = props ?? {};

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

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

export type SubmitSessionRequestMutationResult = NonNullable<
  Awaited<ReturnType<typeof submitSessionRequest>>
>;
export type SubmitSessionRequestMutationBody = BodyType<SessionRequestBody>;
export type SubmitSessionRequestMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Submit a request against a session balance
 */
export const useSubmitSessionRequest = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof submitSessionRequest>>,
    TError,
    { id: string; data: BodyType<SessionRequestBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof submitSessionRequest>>,
  TError,
  { id: string; data: BodyType<SessionRequestBody> },
  TContext
> => {
  return useMutation(getSubmitSessionRequestMutationOptions(options));
};

/**
 * Creates a new Lightning invoice to top up the session balance.
Only one pending topup at a time. Paying it resumes a paused session.

 * @summary Add sats to a session
 */
export const getTopupSessionUrl = (id: string) => {
  return `/api/sessions/${id}/topup`;
};

export const topupSession = async (
  id: string,
  createSessionRequest: CreateSessionRequest,
  options?: RequestInit,
): Promise<TopupSessionResponse> => {
  return customFetch<TopupSessionResponse>(getTopupSessionUrl(id), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createSessionRequest),
  });
};

export const getTopupSessionMutationOptions = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof topupSession>>,
    TError,
    { id: string; data: BodyType<CreateSessionRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof topupSession>>,
  TError,
  { id: string; data: BodyType<CreateSessionRequest> },
  TContext
> => {
  const mutationKey = ["topupSession"];
  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 topupSession>>,
    { id: string; data: BodyType<CreateSessionRequest> }
  > = (props) => {
    const { id, data } = props ?? {};

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

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

export type TopupSessionMutationResult = NonNullable<
  Awaited<ReturnType<typeof topupSession>>
>;
export type TopupSessionMutationBody = BodyType<CreateSessionRequest>;
export type TopupSessionMutationError = ErrorType<ErrorResponse>;

/**
 * @summary Add sats to a session
 */
export const useTopupSession = <
  TError = ErrorType<ErrorResponse>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof topupSession>>,
    TError,
    { id: string; data: BodyType<CreateSessionRequest> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof topupSession>>,
  TError,
  { id: string; data: BodyType<CreateSessionRequest> },
  TContext
> => {
  return useMutation(getTopupSessionMutationOptions(options));
};

/**
 * Runs the agent without payment. Limited to 5 requests per IP per hour.
 * @summary Free demo (rate-limited)
 */
export const getRunDemoUrl = (params: RunDemoParams) => {
  const normalizedParams = new URLSearchParams();

  Object.entries(params || {}).forEach(([key, value]) => {
    if (value !== undefined) {
      normalizedParams.append(key, value === null ? "null" : value.toString());
    }
  });

  const stringifiedParams = normalizedParams.toString();

  return stringifiedParams.length > 0
    ? `/api/demo?${stringifiedParams}`
    : `/api/demo`;
};

export const runDemo = async (
  params: RunDemoParams,
  options?: RequestInit,
): Promise<DemoResponse> => {
  return customFetch<DemoResponse>(getRunDemoUrl(params), {
    ...options,
    method: "GET",
  });
};

export const getRunDemoQueryKey = (params?: RunDemoParams) => {
  return [`/api/demo`, ...(params ? [params] : [])] as const;
};

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

  const queryKey = queryOptions?.queryKey ?? getRunDemoQueryKey(params);

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

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

export type RunDemoQueryResult = NonNullable<
  Awaited<ReturnType<typeof runDemo>>
>;
export type RunDemoQueryError = ErrorType<ErrorResponse>;

/**
 * @summary Free demo (rate-limited)
 */

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

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

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

/**
 * @summary List all conversations
 */
export const getListGeminiConversationsUrl = () => {
  return `/api/gemini/conversations`;
};

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

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

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

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

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

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

export type ListGeminiConversationsQueryResult = NonNullable<
  Awaited<ReturnType<typeof listGeminiConversations>>
>;
export type ListGeminiConversationsQueryError = ErrorType<unknown>;

/**
 * @summary List all conversations
 */

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

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

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

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

export const createGeminiConversation = async (
  createGeminiConversationBody: CreateGeminiConversationBody,
  options?: RequestInit,
): Promise<GeminiConversation> => {
  return customFetch<GeminiConversation>(getCreateGeminiConversationUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(createGeminiConversationBody),
  });
};

export const getCreateGeminiConversationMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof createGeminiConversation>>,
    TError,
    { data: BodyType<CreateGeminiConversationBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof createGeminiConversation>>,
  TError,
  { data: BodyType<CreateGeminiConversationBody> },
  TContext
> => {
  const mutationKey = ["createGeminiConversation"];
  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 createGeminiConversation>>,
    { data: BodyType<CreateGeminiConversationBody> }
  > = (props) => {
    const { data } = props ?? {};

    return createGeminiConversation(data, requestOptions);
  };

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

export type CreateGeminiConversationMutationResult = NonNullable<
  Awaited<ReturnType<typeof createGeminiConversation>>
>;
export type CreateGeminiConversationMutationBody =
  BodyType<CreateGeminiConversationBody>;
export type CreateGeminiConversationMutationError = ErrorType<unknown>;

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

/**
 * @summary Get conversation with messages
 */
export const getGetGeminiConversationUrl = (id: number) => {
  return `/api/gemini/conversations/${id}`;
};

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

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

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

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

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

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

export type GetGeminiConversationQueryResult = NonNullable<
  Awaited<ReturnType<typeof getGeminiConversation>>
>;
export type GetGeminiConversationQueryError = ErrorType<GeminiError>;

/**
 * @summary Get conversation with messages
 */

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

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

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

/**
 * @summary Delete a conversation
 */
export const getDeleteGeminiConversationUrl = (id: number) => {
  return `/api/gemini/conversations/${id}`;
};

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

export const getDeleteGeminiConversationMutationOptions = <
  TError = ErrorType<GeminiError>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteGeminiConversation>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof deleteGeminiConversation>>,
  TError,
  { id: number },
  TContext
> => {
  const mutationKey = ["deleteGeminiConversation"];
  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 deleteGeminiConversation>>,
    { id: number }
  > = (props) => {
    const { id } = props ?? {};

    return deleteGeminiConversation(id, requestOptions);
  };

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

export type DeleteGeminiConversationMutationResult = NonNullable<
  Awaited<ReturnType<typeof deleteGeminiConversation>>
>;

export type DeleteGeminiConversationMutationError = ErrorType<GeminiError>;

/**
 * @summary Delete a conversation
 */
export const useDeleteGeminiConversation = <
  TError = ErrorType<GeminiError>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof deleteGeminiConversation>>,
    TError,
    { id: number },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof deleteGeminiConversation>>,
  TError,
  { id: number },
  TContext
> => {
  return useMutation(getDeleteGeminiConversationMutationOptions(options));
};

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

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

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

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

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

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

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

export type ListGeminiMessagesQueryResult = NonNullable<
  Awaited<ReturnType<typeof listGeminiMessages>>
>;
export type ListGeminiMessagesQueryError = ErrorType<unknown>;

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

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

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

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

/**
 * @summary Send a message and receive an AI response (SSE stream)
 */
export const getSendGeminiMessageUrl = (id: number) => {
  return `/api/gemini/conversations/${id}/messages`;
};

export const sendGeminiMessage = async (
  id: number,
  sendGeminiMessageBody: SendGeminiMessageBody,
  options?: RequestInit,
): Promise<unknown> => {
  return customFetch<unknown>(getSendGeminiMessageUrl(id), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(sendGeminiMessageBody),
  });
};

export const getSendGeminiMessageMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof sendGeminiMessage>>,
    TError,
    { id: number; data: BodyType<SendGeminiMessageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof sendGeminiMessage>>,
  TError,
  { id: number; data: BodyType<SendGeminiMessageBody> },
  TContext
> => {
  const mutationKey = ["sendGeminiMessage"];
  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 sendGeminiMessage>>,
    { id: number; data: BodyType<SendGeminiMessageBody> }
  > = (props) => {
    const { id, data } = props ?? {};

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

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

export type SendGeminiMessageMutationResult = NonNullable<
  Awaited<ReturnType<typeof sendGeminiMessage>>
>;
export type SendGeminiMessageMutationBody = BodyType<SendGeminiMessageBody>;
export type SendGeminiMessageMutationError = ErrorType<unknown>;

/**
 * @summary Send a message and receive an AI response (SSE stream)
 */
export const useSendGeminiMessage = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof sendGeminiMessage>>,
    TError,
    { id: number; data: BodyType<SendGeminiMessageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof sendGeminiMessage>>,
  TError,
  { id: number; data: BodyType<SendGeminiMessageBody> },
  TContext
> => {
  return useMutation(getSendGeminiMessageMutationOptions(options));
};

/**
 * @summary Generate an image from a text prompt
 */
export const getGenerateGeminiImageUrl = () => {
  return `/api/gemini/generate-image`;
};

export const generateGeminiImage = async (
  generateGeminiImageBody: GenerateGeminiImageBody,
  options?: RequestInit,
): Promise<GenerateGeminiImageResponse> => {
  return customFetch<GenerateGeminiImageResponse>(getGenerateGeminiImageUrl(), {
    ...options,
    method: "POST",
    headers: { "Content-Type": "application/json", ...options?.headers },
    body: JSON.stringify(generateGeminiImageBody),
  });
};

export const getGenerateGeminiImageMutationOptions = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof generateGeminiImage>>,
    TError,
    { data: BodyType<GenerateGeminiImageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
  Awaited<ReturnType<typeof generateGeminiImage>>,
  TError,
  { data: BodyType<GenerateGeminiImageBody> },
  TContext
> => {
  const mutationKey = ["generateGeminiImage"];
  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 generateGeminiImage>>,
    { data: BodyType<GenerateGeminiImageBody> }
  > = (props) => {
    const { data } = props ?? {};

    return generateGeminiImage(data, requestOptions);
  };

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

export type GenerateGeminiImageMutationResult = NonNullable<
  Awaited<ReturnType<typeof generateGeminiImage>>
>;
export type GenerateGeminiImageMutationBody = BodyType<GenerateGeminiImageBody>;
export type GenerateGeminiImageMutationError = ErrorType<unknown>;

/**
 * @summary Generate an image from a text prompt
 */
export const useGenerateGeminiImage = <
  TError = ErrorType<unknown>,
  TContext = unknown,
>(options?: {
  mutation?: UseMutationOptions<
    Awaited<ReturnType<typeof generateGeminiImage>>,
    TError,
    { data: BodyType<GenerateGeminiImageBody> },
    TContext
  >;
  request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
  Awaited<ReturnType<typeof generateGeminiImage>>,
  TError,
  { data: BodyType<GenerateGeminiImageBody> },
  TContext
> => {
  return useMutation(getGenerateGeminiImageMutationOptions(options));
};
