package io.vertx.ext.mongo;

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.core.streams.ReadStream;
import io.vertx.core.streams.WriteStream;

import java.util.List;

@VertxGen
public interface MongoGridFsClient {
  /**
   * Deletes a file by it's ID
   *
   * @param id            the identifier of the file
   * @param resultHandler will be called when the file is deleted
   */
  @Fluent
  MongoGridFsClient delete(String id, Handler<AsyncResult<Void>> resultHandler);

  /**
   * Like {@link #delete(String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Void> delete(String id);

  @Fluent
  MongoGridFsClient downloadByFileName(WriteStream<Buffer> stream, String fileName, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadByFileName(WriteStream, String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadByFileName(WriteStream<Buffer> stream, String fileName);

  @Fluent
  MongoGridFsClient downloadByFileNameWithOptions(WriteStream<Buffer> stream, String fileName, GridFsDownloadOptions options, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadByFileNameWithOptions(WriteStream, String, GridFsDownloadOptions, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadByFileNameWithOptions(WriteStream<Buffer> stream, String fileName, GridFsDownloadOptions options);

  @Fluent
  MongoGridFsClient downloadById(WriteStream<Buffer> stream, String id, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadById(WriteStream, String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadById(WriteStream<Buffer> stream, String id);

  /**
   * Downloads a file.
   *
   * @param fileName      the name of the file to download
   * @param resultHandler called when the file is downloaded and returns the length in bytes
   */
  @Fluent
  MongoGridFsClient downloadFile(String fileName, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadFile(String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadFile(String fileName);

  /**
   * Downloads a file and gives it a new name.
   *
   * @param fileName      the name of the file to download
   * @param newFileName   the name the file should be saved as
   * @param resultHandler called when the file is downloaded and returns the length in bytes
   */
  @Fluent
  MongoGridFsClient downloadFileAs(String fileName, String newFileName, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadFileAs(String, String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadFileAs(String fileName, String newFileName);

  /**
   * Downloads a file using the ID generated by GridFs.
   *
   * @param id            the GridFs Object ID of the file to download
   * @param resultHandler called when the file is downloaded and returns the length in bytes
   */
  @Fluent
  MongoGridFsClient downloadFileByID(String id, String fileName, Handler<AsyncResult<Long>> resultHandler);

  /**
   * Like {@link #downloadFileByID(String, String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Long> downloadFileByID(String id, String fileName);

  /**
   * Drops the entire file bucket with all of its contents
   *
   * @param resultHandler called when the bucket is dropped
   */
  @Fluent
  MongoGridFsClient drop(Handler<AsyncResult<Void>> resultHandler);

  /**
   * Like {@link #drop(Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<Void> drop();

  /**
   * Finds all file ids in the bucket
   *
   * @param resultHandler called when the list of file ids is available
   */
  @Fluent
  MongoGridFsClient findAllIds(Handler<AsyncResult<List<String>>> resultHandler);

  /**
   * Like {@link #findAllIds(Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<List<String>> findAllIds();

  /**
   * Finds all file ids that match a query.
   *
   * @param query         a bson query expressed as json that will be used to match files
   * @param resultHandler called when the list of file ids is available
   */
  @Fluent
  MongoGridFsClient findIds(JsonObject query, Handler<AsyncResult<List<String>>> resultHandler);

  /**
   * Like {@link #findIds(JsonObject, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<List<String>> findIds(JsonObject query);

  @Fluent
  MongoGridFsClient uploadByFileName(ReadStream<Buffer> stream, String fileName, Handler<AsyncResult<String>> resultHandler);

  /**
   * Like {@link #uploadByFileName(ReadStream, String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<String> uploadByFileName(ReadStream<Buffer> stream, String fileName);

  @Fluent
  MongoGridFsClient uploadByFileNameWithOptions(ReadStream<Buffer> stream, String fileName, GridFsUploadOptions options, Handler<AsyncResult<String>> resultHandler);

  /**
   * Like {@link #uploadByFileNameWithOptions(ReadStream, String, GridFsUploadOptions, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<String> uploadByFileNameWithOptions(ReadStream<Buffer> stream, String fileName, GridFsUploadOptions options);

  /**
   * Upload a file to gridfs
   *
   * @param fileName      the name of the file to store in gridfs
   * @param resultHandler the id of the file that was uploaded
   */
  @Fluent
  MongoGridFsClient uploadFile(String fileName, Handler<AsyncResult<String>> resultHandler);

  /**
   * Like {@link #uploadFile(String, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<String> uploadFile(String fileName);

  /**
   * Upload a file to gridfs with options
   *
   * @param fileName      the name of the file to store in gridfs
   * @param options       {@link GridFsUploadOptions} for specifying metadata and chunk size
   * @param resultHandler the id of the file that was uploaded
   */
  @Fluent
  MongoGridFsClient uploadFileWithOptions(String fileName, GridFsUploadOptions options, Handler<AsyncResult<String>> resultHandler);

  /**
   * Like {@link #uploadFileWithOptions(String, GridFsUploadOptions, Handler)} but returns a {@code Future} of the asynchronous result
   */
  Future<String> uploadFileWithOptions(String fileName, GridFsUploadOptions options);

  /**
   * Close the client and release its resources
   */
  void close();
}
