/**
 * SpawnManager.js
 * Manages enemy tank spawning: timing, spawn points, composition, and limits.
 */

const EnemyTank = require('../entities/EnemyTank');
const {
  TANK_TYPE,
  MAX_ENEMIES_ON_SCREEN,
  ENEMY_SPAWN_INTERVAL,
  TILE_SIZE,
  MAP_OFFSET_X,
  MAP_OFFSET_Y,
  GRID_COLS,
} = require('../base/GameGlobal');

class SpawnManager {
  constructor() {
    /** @type {Array<{col: number, row: number}>} */
    this._spawnPoints = [];
    this._currentSpawnIndex = 0;

    // Spawn queue
    this._spawnQueue = []; // array of TANK_TYPE values
    this._spawnTimer = 0;
    this._spawnInterval = ENEMY_SPAWN_INTERVAL;
    this._totalSpawned = 0;
    this._totalEnemies = 0;

    // Level info
    this._levelNum = 1;

    // Power-up enemy indices (which enemies drop power-ups)
    this._powerUpIndices = new Set();
  }

  /**
   * Initialize for a new level.
   * @param {object} levelData - Level configuration from LevelData.
   */
  init(levelData) {
    this._spawnPoints = levelData.spawnPoints || [
      { col: 0, row: 0 },
      { col: Math.floor(GRID_COLS / 2), row: 0 },
      { col: GRID_COLS - 1, row: 0 },
    ];
    this._currentSpawnIndex = 0;
    this._spawnTimer = 0;
    this._totalSpawned = 0;
    this._levelNum = levelData.id || 1;
    this._speedMultiplier = levelData.speedMultiplier || 1;

    // Build spawn queue from composition
    this._spawnQueue = [];
    const comp = levelData.enemies.composition;
    this._totalEnemies = levelData.enemies.total;

    // Add enemies by type
    for (let i = 0; i < (comp.boss || 0); i++) this._spawnQueue.push(TANK_TYPE.ENEMY_BOSS);
    for (let i = 0; i < (comp.armor || 0); i++) this._spawnQueue.push(TANK_TYPE.ENEMY_ARMOR);
    for (let i = 0; i < (comp.fast || 0); i++) this._spawnQueue.push(TANK_TYPE.ENEMY_FAST);
    for (let i = 0; i < (comp.normal || 0); i++) this._spawnQueue.push(TANK_TYPE.ENEMY_NORMAL);

    // Shuffle the queue for variety
    this._shuffleArray(this._spawnQueue);

    // Determine which enemies drop power-ups (roughly every 4-5 enemies)
    this._powerUpIndices.clear();
    const numPowerUps = Math.max(1, Math.floor(this._totalEnemies / 5));
    const indices = new Set();
    while (indices.size < numPowerUps) {
      indices.add(Math.floor(Math.random() * this._totalEnemies));
    }
    this._powerUpIndices = indices;

    // Spawn first batch immediately
    this._spawnTimer = this._spawnInterval;
  }

  /**
   * Update spawn timer and spawn enemies as needed.
   * @param {number} dt - Delta time in seconds.
   * @param {Array<EnemyTank>} activeEnemies - Currently alive enemies.
   * @returns {EnemyTank|null} Newly spawned enemy, or null.
   */
  update(dt, activeEnemies) {
    if (this._spawnQueue.length === 0) return null;

    const aliveCount = activeEnemies.filter((e) => e.alive).length;
    if (aliveCount >= MAX_ENEMIES_ON_SCREEN) return null;

    this._spawnTimer += dt * 1000;
    if (this._spawnTimer < this._spawnInterval) return null;

    this._spawnTimer = 0;
    return this._spawnNext();
  }

  /**
   * Spawn the next enemy from the queue.
   * @private
   * @returns {EnemyTank|null}
   */
  _spawnNext() {
    if (this._spawnQueue.length === 0) return null;

    const type = this._spawnQueue.shift();
    const spawnPoint = this._spawnPoints[this._currentSpawnIndex % this._spawnPoints.length];
    this._currentSpawnIndex++;

    const hasPowerUp = this._powerUpIndices.has(this._totalSpawned);
    this._totalSpawned++;

    const enemy = new EnemyTank({
      type,
      col: spawnPoint.col,
      row: spawnPoint.row,
      levelNum: this._levelNum,
      hasPowerUp,
      speedMultiplier: this._speedMultiplier,
    });

    return enemy;
  }

  /**
   * Fisher-Yates shuffle.
   * @private
   */
  _shuffleArray(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
  }

  /** Number of enemies remaining to spawn. */
  get remainingToSpawn() {
    return this._spawnQueue.length;
  }

  /** Total enemies for this level. */
  get totalEnemies() {
    return this._totalEnemies;
  }

  /** Total spawned so far. */
  get totalSpawned() {
    return this._totalSpawned;
  }

  /** Whether all enemies have been spawned. */
  get allSpawned() {
    return this._spawnQueue.length === 0;
  }
}

module.exports = SpawnManager;
