import { Value } from "../../values";
import { GenericAPI, NamedQuery, QueryNames } from "../../api";

/**
 * A view of the query results currently in the Convex client for use within
 * optimistic updates.
 *
 * @public
 */
export interface OptimisticLocalStore<API extends GenericAPI = GenericAPI> {
  /**
   * Retrieve the result of a query from the client.
   *
   * Important: Query results should be treated as immutable!
   * Always make new copies of structures within query results to avoid
   * corrupting data within the client.
   *
   * @param name - The name of the query.
   * @param args - An array of the arguments for this query.
   * @returns The query result or `undefined` if the query is not currently
   * in the client.
   */
  getQuery<Name extends QueryNames<API>>(
    name: Name,
    args: Parameters<NamedQuery<API, Name>>
  ): undefined | ReturnType<NamedQuery<API, Name>>;

  /**
   * Retrieve the results are arguments of all queries with a given name.
   *
   * This is useful for complex optimistic updates that need to inspect and
   * update many query results (for example updating a paginated list).
   *
   * Important: Query results should be treated as immutable!
   * Always make new copies of structures within query results to avoid
   * corrupting data within the client.
   * @param name - The name of the query.
   * @returns An array of objects, one for each query of the given name.
   * Each object includes:
   *   - `args` - An array of the arguments to the query.
   *   - `value` The query result or `undefined` if the query is loading.
   */
  getAllQueries<Name extends QueryNames<API>>(
    name: Name
  ): {
    args: Parameters<NamedQuery<API, Name>>;
    value: undefined | ReturnType<NamedQuery<API, Name>>;
  }[];

  /**
   * Optimistically update the result of a query.
   *
   * This can either be a new value (perhaps derived from the old value from
   * {@link OptimisticLocalStore.getQuery}) or `undefined` to remove the query.
   * Removing a query is useful to create loading states while Convex recomputes
   * the query results.
   *
   * @param name - The name of the query.
   * @param args - An array of the arguments for this query.
   * @param value - The new value to set the query to or `undefined` to remove
   * it from the client.
   */
  setQuery<Name extends QueryNames<API>>(
    name: Name,
    args: Parameters<NamedQuery<API, Name>>,
    value: undefined | ReturnType<NamedQuery<API, Name>>
  ): void;
}
/**
 * A temporary, local update to query results within this client.
 *
 * This update will always be executed when a mutation is synced to the Convex
 * server and rolled back when the mutation completes.
 *
 * Note that optimistic updates can be called multiple times! If the client
 * loads new data while the mutation is in progress, the update will be replayed
 * again.
 *
 * @param localQueryStore - An interface to read and edit local query results.
 * @param args - The arguments to the mutation.
 *
 * @public
 */
export type OptimisticUpdate<
  API extends GenericAPI,
  Arguments extends Value[]
> = (localQueryStore: OptimisticLocalStore<API>, ...args: Arguments) => void;
