import { baseApi } from '../base-api';

export type ApiQueryArgs = {
  url: string;
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  params?: Record<string, unknown>;
  body?: unknown;
  headers?: Record<string, string>;
  cacheKey?: string | unknown[];
};

const queryApi = baseApi.injectEndpoints({
  endpoints: (builder) => ({
    apiQuery: builder.query<unknown, ApiQueryArgs>({
      query: ({ url, params }) => ({ url, params }),
    }),
    apiMutation: builder.mutation<unknown, ApiQueryArgs>({
      query: ({ url, method = 'POST', body, headers }) => ({
        url,
        method,
        body,
        headers,
      }),
    }),
  }),
  overrideExisting: false,
});

export const { useApiQueryQuery, useLazyApiQueryQuery, useApiMutationMutation } = queryApi;

export function useApiQuery<TData = unknown>(
  args: ApiQueryArgs,
  options?: Parameters<typeof useApiQueryQuery>[1],
) {
  return useApiQueryQuery(args, options) as ReturnType<typeof useApiQueryQuery> & {
    data: TData | undefined;
  };
}

/**
 * Same endpoint as `useApiQuery`, fetched on demand instead of on render — for
 * the case where the arguments are only known at click time.
 */
export function useApiLazyQuery<TData = unknown>(): [
  (args: ApiQueryArgs) => { unwrap: () => Promise<TData> },
] {
  const [trigger] = useLazyApiQueryQuery();
  return [trigger as unknown as (args: ApiQueryArgs) => { unwrap: () => Promise<TData> }];
}

type UseApiMutationResult<TData> = {
  data: TData | undefined;
  isLoading: boolean;
  isError: boolean;
  error: unknown;
  isSuccess: boolean;
  status: 'uninitialized' | 'pending' | 'fulfilled' | 'rejected';
  reset: () => void;
};

export function useApiMutation<TData = unknown>(): [
  (args: ApiQueryArgs) => Promise<{ data: TData }> & { unwrap: () => Promise<TData> },
  UseApiMutationResult<TData>,
] {
  return useApiMutationMutation() as unknown as [
    (args: ApiQueryArgs) => Promise<{ data: TData }> & { unwrap: () => Promise<TData> },
    UseApiMutationResult<TData>,
  ];
}
