import { Platform } from '../entities/Platform.js';
import { Spring } from '../entities/Spring.js';
import { PropellerHat } from '../entities/PropellerHat.js';
import { Rocket } from '../entities/Rocket.js';
import { Enemy } from '../entities/Enemy.js';
import { rng } from '../utils/random.js';
import {
  GAME_WIDTH, PLATFORM_GAP_MIN, PLATFORM_GAP_MAX,
  SPAWN_RATES, POWERUP_RATES, ENEMY_RATES, DIFFICULTY, UNLOCK,
} from '../config/game.config.js';

export class PlatformManager {
  constructor(scene) {
    this.scene = scene;
    this.platforms = scene.add.group({ classType: Platform });
    this.enemies = scene.add.group({ classType: Enemy });
    this.powerups = scene.add.group();
    this.lastY = scene.scale.height - 80;
    this.highestY = this.lastY;
  }

  update(difficultyLevel, killLine) {
    const camY = this.scene.cameras.main.scrollY;
    let maxPerFrame = 5;
    while (this.highestY > camY - 250 && maxPerFrame-- > 0) {
      this.spawnPlatform(difficultyLevel);
    }

    this.cleanupGroup(this.platforms, killLine);
    this.cleanupGroup(this.enemies, killLine);
    this.cleanupGroup(this.powerups, killLine);
  }

  cleanupGroup(group, killLine) {
    const toDestroy = [];
    group.children.iterate((obj) => {
      if (obj && obj.y + obj.displayHeight / 2 > killLine) {
        toDestroy.push(obj);
      }
    });
    toDestroy.forEach((obj) => obj.destroy());
  }

  spawnPlatform(difficultyLevel) {
    const gapIncrease = Math.min(
      Math.floor(difficultyLevel / 1000) * DIFFICULTY.gapIncreasePer1000,
      DIFFICULTY.maxGap - DIFFICULTY.initialGap
    );
    const gap = rng.between(
      PLATFORM_GAP_MIN + gapIncrease,
      Math.min(PLATFORM_GAP_MAX + gapIncrease, DIFFICULTY.maxGap)
    );
    this.highestY -= gap;

    const x = rng.between(60, GAME_WIDTH - 60);
    const rand = rng.frac();
    let type;
    if (rand < SPAWN_RATES.stable) type = 'stable';
    else if (rand < SPAWN_RATES.stable + SPAWN_RATES.moving) type = 'moving';
    else if (rand < SPAWN_RATES.stable + SPAWN_RATES.moving + SPAWN_RATES.breaking) type = 'breaking';
    else if (rand < SPAWN_RATES.stable + SPAWN_RATES.moving + SPAWN_RATES.breaking + SPAWN_RATES.reorg) type = 'reorg';
    else type = 'genesis';

    // Phantom reorg platforms only appear once the climb gets serious.
    if (type === 'reorg' && difficultyLevel < UNLOCK.reorg) type = 'stable';

    const platform = new Platform(this.scene, x, this.highestY, type);
    this.platforms.add(platform);

    // No power-ups on platforms that disappear under you.
    if (type !== 'breaking' && type !== 'reorg') {
      this.maybeSpawnPowerUp(x, this.highestY - 25);
    }
    this.maybeSpawnEnemy(x, this.highestY, difficultyLevel);
  }

  maybeSpawnPowerUp(platformX, y) {
    const rand = rng.frac();
    let type = null;
    if (rand < POWERUP_RATES.spring) type = 'spring';
    else if (rand < POWERUP_RATES.spring + POWERUP_RATES.propeller) type = 'propeller';
    else if (rand < POWERUP_RATES.spring + POWERUP_RATES.propeller + POWERUP_RATES.rocket) type = 'rocket';

    if (!type) return;

    const x = Phaser.Math.Clamp(platformX + rng.between(-15, 15), 30, GAME_WIDTH - 30);
    if (type === 'spring') {
      this.powerups.add(new Spring(this.scene, x, y));
    } else if (type === 'propeller') {
      this.powerups.add(new PropellerHat(this.scene, x, y - 35));
    } else if (type === 'rocket') {
      this.powerups.add(new Rocket(this.scene, x, y - 45));
    }
  }

  maybeSpawnEnemy(platformX, platformY, difficultyLevel) {
    const enemyBonus = Math.min(
      Math.floor(difficultyLevel / 1000) * DIFFICULTY.enemyIncreasePer1000,
      DIFFICULTY.maxEnemyRate
    );
    const totalRate = Math.min(ENEMY_RATES.bug + enemyBonus, DIFFICULTY.maxEnemyRate);
    if (rng.frac() >= totalRate) return;

    const type = this._rollEnemyType(difficultyLevel);

    const offset = rng.between(-60, 60);
    const ex = Phaser.Math.Clamp(platformX + offset, 50, GAME_WIDTH - 50);
    const ey = platformY - rng.between(60, 130);

    const minDist = 150;
    let tooClose = false;
    this.enemies.children.iterate((e) => {
      if (e && Phaser.Math.Distance.Between(ex, ey, e.x, e.y) < minDist) {
        tooClose = true;
      }
    });
    if (tooClose) return;

    this.enemies.add(new Enemy(this.scene, ex, ey, type));
  }

  _rollEnemyType(difficultyLevel) {
    const r = rng.frac();
    if (difficultyLevel >= UNLOCK.mevBot) {
      if (r < 0.25) return 'mev_bot';
      if (r < 0.50) return 'failed_tx';
      return 'bug';
    }
    if (difficultyLevel >= UNLOCK.failedTx) {
      return r < 0.30 ? 'failed_tx' : 'bug';
    }
    return 'bug';
  }

  getPlatforms() {
    return this.platforms;
  }

  getEnemies() {
    return this.enemies;
  }

  getPowerups() {
    return this.powerups;
  }
}
