/**
 * ObjectPool.js
 * Generic object pool for reusing frequently created/destroyed objects
 * (bullets, explosions, etc.) to avoid GC pressure in WeChat mini game.
 */

class ObjectPool {
  /**
   * @param {Function} createFn - Factory function that returns a new object instance.
   * @param {Function} [resetFn] - Optional function to reset an object before reuse.
   * @param {number} [initialSize=0] - Number of objects to pre-allocate.
   */
  constructor(createFn, resetFn, initialSize = 0) {
    this._createFn = createFn;
    this._resetFn = resetFn || null;
    this._pool = [];
    this._activeCount = 0;

    // Pre-allocate
    for (let i = 0; i < initialSize; i++) {
      this._pool.push(this._createFn());
    }
  }

  /**
   * Get an object from the pool. Creates a new one if pool is empty.
   * @returns {*} A reusable object instance.
   */
  get() {
    let obj;
    if (this._pool.length > 0) {
      obj = this._pool.pop();
    } else {
      obj = this._createFn();
    }
    if (this._resetFn) {
      this._resetFn(obj);
    }
    this._activeCount++;
    return obj;
  }

  /**
   * Return an object back to the pool for future reuse.
   * @param {*} obj - The object to recycle.
   */
  put(obj) {
    if (obj) {
      this._pool.push(obj);
      this._activeCount = Math.max(0, this._activeCount - 1);
    }
  }

  /**
   * Pre-allocate a number of objects into the pool.
   * @param {number} count
   */
  preAllocate(count) {
    for (let i = 0; i < count; i++) {
      this._pool.push(this._createFn());
    }
  }

  /**
   * Clear the pool entirely.
   */
  clear() {
    this._pool.length = 0;
    this._activeCount = 0;
  }

  /** Number of objects currently in the pool (idle). */
  get size() {
    return this._pool.length;
  }

  /** Number of objects currently in use. */
  get activeCount() {
    return this._activeCount;
  }
}

module.exports = ObjectPool;
