import type ShellAuthOptions from './shell-auth-options';
import type {
  MongoClientOptions,
  ReadConcern,
  ReadPreference,
  WriteConcern,
  Document,
  CreateCollectionOptions,
  ClientSession,
  DbOptions,
  ClientSessionOptions,
  ListDatabasesOptions,
  AutoEncryptionOptions,
  Collection,
} from './all-transport-types';
import type { ConnectionExtraInfo } from './index';
import type { ReplPlatform } from './platform';
import type {
  AWSEncryptionKeyOptions,
  AzureEncryptionKeyOptions,
  ClientEncryption as MongoCryptClientEncryption,
  ClientEncryptionDataKeyProvider,
  GCPEncryptionKeyOptions,
  ClientEncryption,
  ClientEncryptionOptions,
} from './all-fle-types';
import type { BSON } from '@mongosh/shell-bson';

export interface CreateEncryptedCollectionOptions {
  provider: ClientEncryptionDataKeyProvider;
  createCollectionOptions: Omit<CreateCollectionOptions, 'encryptedFields'> & {
    encryptedFields: Document;
  };
  masterKey?:
    | AWSEncryptionKeyOptions
    | AzureEncryptionKeyOptions
    | GCPEncryptionKeyOptions;
}

export interface CheckMetadataConsistencyOptions {
  cursor?: {
    batchSize: number;
  };
  checkIndexes?: 1;
}

export interface ConnectionInfo {
  buildInfo: Document | null;
  resolvedHostname?: string;
  extraInfo: (ConnectionExtraInfo & { fcv?: string }) | null;
}

export default interface Admin {
  /**
   * What platform (Compass/CLI/Browser)
   */
  platform: ReplPlatform;

  /**
   * The initial database
   */
  initialDb: string;

  /**
   * The BSON package
   */
  bsonLibrary: BSON;

  /**
   * Compute a hex MD5 hash from a string. Used for legacy auth mechanisms such as
   * SCRAM-SHA-1.
   */
  computeLegacyHexMD5?(str: string): Promise<string>;

  /**
   * list databases.
   *
   * @param {String} database - The database name.
   *
   * @returns {Promise} The promise of command Documents.
   */
  listDatabases(
    database: string,
    options?: ListDatabasesOptions
  ): Promise<Document>;

  /**
   * create a new service provider with a new connection.
   *
   * @param uri
   * @param options
   */
  getNewConnection(uri: string, options: MongoClientOptions): Promise<any>; // returns the ServiceProvider instance

  /**
   * Return the URI for the current connection, if this ServiceProvider is connected.
   */
  getURI(): string | undefined;

  /**
   * Return connection info
   */
  getConnectionInfo(): Promise<ConnectionInfo>;

  /**
   * Authenticate
   */
  authenticate(authDoc: ShellAuthOptions): Promise<{ ok: number }>;

  /**
   * createCollection
   */
  createCollection(
    dbName: string,
    collName: string,
    options: CreateCollectionOptions,
    dbOptions?: DbOptions
  ): Promise<{ ok: number }>;

  /**
   * Return read preference for connection.
   */
  getReadPreference(): ReadPreference;

  /**
   * Return read concern for connection.
   */
  getReadConcern(): ReadConcern | undefined;

  /**
   * Return write concern for connection.
   */
  getWriteConcern(): WriteConcern | undefined;

  /**
   * Reset the connection to have the option specified.
   *
   * @param options
   */
  resetConnectionOptions(options: MongoClientOptions): Promise<void>;

  /**
   * Start a session.
   * @param options
   */
  startSession(options: ClientSessionOptions): ClientSession;

  /**
   * Return the raw client for use in keyVaultClient.
   */
  getRawClient(): any;

  /**
   * The FLE implementation for access to the client-side encryption API.
   */
  createClientEncryption?(options: ClientEncryptionOptions): ClientEncryption;

  /**
   * The FLE options passed to the client, if any.
   */
  getFleOptions?: () => AutoEncryptionOptions | undefined;

  /**
   * The helper method to correctly access FLE implementation's createEncryptedCollection
   */
  createEncryptedCollection?(
    dbName: string,
    collName: string,
    options: CreateEncryptedCollectionOptions,
    libmongocrypt: MongoCryptClientEncryption
  ): Promise<{ collection: Collection; encryptedFields: Document }>;
}
