import { commitinfo } from './00_commitinfo_data.js';
import * as plugins from './smartmongo.plugins.js';

export class SmartMongo {
  // STATIC
  public static async createAndStart(replCountArg: number = 1) {
    const smartMongoInstance = new SmartMongo();
    await smartMongoInstance.start(replCountArg);
    return smartMongoInstance;
  }

  // INSTANCE
  private _readyDeferred = plugins.smartpromise.defer();
  public readyPromise = this._readyDeferred.promise;
  public mongoReplicaSet: plugins.mongoPlugin.MongoMemoryReplSet;

  constructor() {}

  public async start(countArg: number = 1) {
    this.mongoReplicaSet = await plugins.mongoPlugin.MongoMemoryReplSet.create({
      replSet: { count: countArg },
      instanceOpts: [
        {
          storageEngine: 'wiredTiger',
        },
      ],
    });
    this._readyDeferred.resolve();
    console.log(`mongoReplicaSet with ${countArg} replicas started.`);
    console.log(`@pushrocks/smartmongo version ${commitinfo.version}`);
  }

  /**
   * returns a mongo descriptor for modules like
   * @pushrocks/smartfile.
   */
  public async getMongoDescriptor(): Promise<plugins.smartdata.IMongoDescriptor> {
    await this.readyPromise;
    return {
      mongoDbName: `smartmongo_testdatabase`,
      mongoDbUrl: this.mongoReplicaSet.getUri(),
    };
  }

  /**
   * stops the smartmongo instance
   * and cleans up after itself
   */
  public async stop() {
    await this.mongoReplicaSet.stop();
    await this.mongoReplicaSet.cleanup();
  }

  /**
   * like stop() but allows you to actually store
   * the database on disk
   */
  public async stopAndDumpToDir(
    dirArg: string,
    nameFunctionArg?: (doc: any) => string,
    emptyDirArg = true,
  ) {
    const mongodumpInstance = new plugins.mongodump.MongoDump();
    const mongodumpTarget = await mongodumpInstance.addMongoTargetByMongoDescriptor(
      await this.getMongoDescriptor(),
    );
    await mongodumpTarget.dumpAllCollectionsToDir(dirArg, nameFunctionArg, emptyDirArg);
    await mongodumpInstance.stop();
    await this.stop();
  }
}