import { SmartDataDbDoc } from './classes.doc.js';
import * as plugins from './plugins.js';

/**
 * a wrapper for the native mongodb cursor. Exposes better
 */
export class SmartdataDbCursor<T = any> {
  // STATIC

  // INSTANCE
  public mongodbCursor: plugins.mongodb.FindCursor<T>;
  private smartdataDbDoc: typeof SmartDataDbDoc;
  constructor(cursorArg: plugins.mongodb.FindCursor<T>, dbDocArg: typeof SmartDataDbDoc) {
    this.mongodbCursor = cursorArg;
    this.smartdataDbDoc = dbDocArg;
  }

  public async next(closeAtEnd = true): Promise<T> {
    const result = this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(
      await this.mongodbCursor.next(),
    );
    if (!result && closeAtEnd) {
      await this.close();
    }
    return result as T;
  }

  public async forEach(forEachFuncArg: (itemArg: T) => Promise<any>, closeCursorAtEnd = true) {
    let nextDocument: any;
    do {
      nextDocument = await this.mongodbCursor.next();
      if (nextDocument) {
        const nextClassInstance =
          this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(nextDocument);
        await forEachFuncArg(nextClassInstance as any);
      }
    } while (nextDocument);
    if (closeCursorAtEnd) {
      await this.close();
    }
  }

  public async toArray(): Promise<T[]> {
    const result = await this.mongodbCursor.toArray();
    return result.map((itemArg) => this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(itemArg)) as T[];
  }

  public async close() {
    await this.mongodbCursor.close();
  }
}