import { Player } from '../entities/Player.js';
import { WaveManager } from '../systems/WaveManager.js';
import { XPSystem } from '../systems/XPSystem.js';
import { SkillTree } from '../systems/SkillTree.js';
import { HUD } from '../ui/HUD.js';
import { SkillTreeUI } from '../ui/SkillTreeUI.js';
import { Reticle } from '../ui/Reticle.js';
import { BarrierManager } from '../systems/BarrierManager.js';

const ZONE_PALETTE = [
  null, // index 0 unused
  { bg: 0x111118, grid: 0x222233, gridAlpha: 0.50, border: 0x334466, shimmer: null     }, // zone 1 — dark blue-grey (unchanged)
  { bg: 0x080d28, grid: 0x1a3488, gridAlpha: 0.70, border: 0x2255dd, shimmer: 0x00eeff }, // zone 2 — deep navy
  { bg: 0x0e0828, grid: 0x2a1888, gridAlpha: 0.70, border: 0x6633cc, shimmer: 0x8833ff }, // zone 3 — indigo
  { bg: 0x160828, grid: 0x420aaa, gridAlpha: 0.70, border: 0x9922dd, shimmer: 0xff00ff }, // zone 4 — deep violet
  { bg: 0x1e0820, grid: 0x5a0e55, gridAlpha: 0.70, border: 0xcc22aa, shimmer: 0xff2266 }, // zone 5 — dark magenta
  { bg: 0x1e0e06, grid: 0x552208, gridAlpha: 0.70, border: 0xdd5511, shimmer: 0xff7700 }, // zone 6 — burnt amber
];

export class GameScene extends Phaser.Scene {
  constructor() {
    super({ key: 'GameScene' });
  }

  preload() {
    this.load.json('zones', './js/data/zones.json');
    this.load.json('skillTree', './js/data/skillTree.json');
    this.load.spritesheet('player', './assets/sprites/player.png', { frameWidth: 48, frameHeight: 48 });
    this.load.spritesheet('enemies', './assets/sprites/enemies.png', { frameWidth: 48, frameHeight: 48 });
    this.load.audio('music-game', './assets/music/gameBackground.mp3');
    this.load.audio('sfx-edge-remove', './assets/fx/EdgeRemove.mp3');
    this.load.audio('sfx-arrow-ping', './assets/fx/ArrowPing.mp3');
    this.load.audio('sfx-sprayer-shoot', './assets/fx/SprayerShoot.mp3');
    this.load.audio('sfx-death',       './assets/fx/Death.mp3');
    this.load.audio('sfx-new-life',    './assets/fx/NewLife.mp3');
    this.load.audio('sfx-shoot',       './assets/fx/Shoot.mp3');
    this.load.audio('sfx-take-damage', './assets/fx/TakeDamage.mp3');
    this.load.audio('sfx-shooter-shoot', './assets/fx/ShooterShoot.mp3');
    this.load.audio('sfx-enemy-wave', './assets/fx/EnemyWave.mp3');
    this.load.audio('sfx-death-chaser', './assets/fx/EnemyChaseDeath.mp3');
    this.load.audio('sfx-death-swarmer', './assets/fx/EnemySwarmerDeath.mp3');
    this.load.audio('sfx-death-shooter', './assets/fx/EnemyShooterDeath.mp3');
    this.load.audio('sfx-death-sprayer', './assets/fx/EnemySprayerDeath.mp3');
    this.load.audio('sfx-death-bomber', './assets/fx/EnemyBomberDeath.mp3');
  }

  create() {
    const W = this.scale.width;
    const H = this.scale.height;

    this._drawArena(W, H);

    this.physics.world.setBounds(0, 0, W, H);

    // Core systems — data already loaded by preload()
    this.skillTree = new SkillTree();
    this.skillTree.load(this.cache.json.get('skillTree'));

    this.player = new Player(this, W / 2, H / 2);

    this.xpSystem = new XPSystem(this);

    this.waveManager = new WaveManager(this, this.player);
    this.waveManager.load(this.cache.json.get('zones'));

    this.hud = new HUD(this, this.player, this.xpSystem);

    // Enemy projectile group for collision
    this._enemyProjectiles = [];

    // Event wiring
    this.events.on('enemy-killed', ({ xp }) => this.xpSystem.addXP(xp));
    this.events.on('enemy-projectile-spawned', proj => this._enemyProjectiles.push(proj));
    this.events.on('level-up', level => this._showLevelUp(level));
    this.events.on('game-over', () => this._onGameOver());
    this.events.on('victory', () => this._onVictory());

    this._levelUpPending = false;
    this._frozen = false;
    this._waitingForExit = false;
    this._pulseEffects = [];
    this._shimmers = [];
    this._shimmerTimer = 0;
    this._shimmerSpawnMs = 1500;

    this.events.on('wave-start', () => this.sound.play('sfx-enemy-wave', { volume: 0.5 }));
    this.events.on('zone-waves-complete', () => this._startZoneExit());

    this.reticle = new Reticle(this);

    this._setupBarriers();

    this._bgMusic = this.sound.add('music-game', { loop: true, volume: 0.8 });
    this._bgMusic.play();

    this.waveManager.start();
  }

  _setupBarriers() {
    // Remove old colliders before destroying the groups they reference
    if (this._barrierColliders) {
      this._barrierColliders.forEach(c => c.destroy());
    }
    this.barrierManager?.destroy();

    const zoneData = this.waveManager.currentZone ?? this.waveManager.zones[0];
    const interiorCount = zoneData?.interiorBarriers ?? 0;
    this.barrierManager = new BarrierManager(this, interiorCount);

    // Player blocked by all barriers; enemies only blocked by interior ones
    this._barrierColliders = [
      this.physics.add.collider(this.player.sprite, this.barrierManager.staticGroup),
      this.physics.add.collider(this.waveManager.spriteGroup, this.barrierManager.interiorStaticGroup),
    ];

    this.barrierManager.activateEdgeBarriers(() => {
      const W = this.scale.width;
      const H = this.scale.height;
      if (this.barrierManager.isInsideEdgeBarrier(this.player.x, this.player.y)) {
        this.player.sprite.body.reset(W / 2, H / 2);
        this.player.takeDamage(this.player.hp); // lose a life, respawn at center
      }
    });
  }

  _drawArena(W, H) {
    this._arenaBg = this.add.rectangle(W / 2, H / 2, W, H, 0x111118);
    this._arenaGrid = this.add.graphics();
    const z1 = ZONE_PALETTE[1];
    this._drawArenaGrid(z1.grid, z1.gridAlpha, z1.border);
  }

  _drawArenaGrid(gridColor, gridAlpha, borderColor) {
    const W = this.scale.width;
    const H = this.scale.height;
    this._arenaGrid.clear();
    this._arenaGrid.lineStyle(1, gridColor, gridAlpha);
    for (let x = 0; x <= W; x += 80) { this._arenaGrid.lineBetween(x, 0, x, H); }
    for (let y = 0; y <= H; y += 80) { this._arenaGrid.lineBetween(0, y, W, y); }
    this._arenaGrid.lineStyle(3, borderColor, 1);
    this._arenaGrid.strokeRect(2, 2, W - 4, H - 4);
  }

  _updateArenaColors(zoneNum) {
    const palette = ZONE_PALETTE[zoneNum] ?? ZONE_PALETTE[ZONE_PALETTE.length - 1];
    this._arenaBg.setFillStyle(palette.bg);
    this._drawArenaGrid(palette.grid, palette.gridAlpha, palette.border);
  }

  _spawnShimmer() {
    const zoneNum = this.waveManager.zoneNum;
    if (zoneNum < 2) return;
    if (this._shimmers.length >= 2) return;
    const palette = ZONE_PALETTE[Math.min(zoneNum, ZONE_PALETTE.length - 1)];
    if (!palette?.shimmer) return;

    const COLS = Math.floor(this.scale.width / 80);
    const ROWS = Math.floor(this.scale.height / 80);
    const col = Phaser.Math.Between(0, COLS - 1);
    const row = Phaser.Math.Between(0, ROWS - 1);

    const rect = this.add.rectangle(
      col * 80 + 40, row * 80 + 40, 80, 80, palette.shimmer, 0
    ).setDepth(1);

    this._shimmers.push({
      rect, col, row,
      stepTimer: 0,
      stepMs: Phaser.Math.Between(250, 400),
      stepsLeft: Phaser.Math.Between(5, 9),
      phase: 'fadein',
      phaseTimer: 0,
    });
  }

  _updateShimmers(delta) {
    if (this.waveManager.zoneNum < 2) return;

    this._shimmerTimer += delta;
    if (this._shimmerTimer >= this._shimmerSpawnMs) {
      this._shimmerTimer = 0;
      this._shimmerSpawnMs = Phaser.Math.Between(3000, 6000);
      this._spawnShimmer();
    }

    const COLS = Math.floor(this.scale.width / 80);
    const ROWS = Math.floor(this.scale.height / 80);
    const TARGET_ALPHA = 0.22;
    const FADE_IN_MS = 150;
    const FADE_OUT_MS = 350;

    this._shimmers = this._shimmers.filter(s => {
      s.phaseTimer += delta;

      if (s.phase === 'fadein') {
        s.rect.fillAlpha = Math.min(1, s.phaseTimer / FADE_IN_MS) * TARGET_ALPHA;
        if (s.phaseTimer >= FADE_IN_MS) {
          s.phase = 'walk';
          s.phaseTimer = 0;
          s.stepTimer = 0;
        }
      } else if (s.phase === 'walk') {
        s.stepTimer += delta;
        if (s.stepTimer >= s.stepMs) {
          s.stepTimer = 0;
          s.stepsLeft--;
          if (s.stepsLeft <= 0) {
            s.phase = 'fadeout';
            s.phaseTimer = 0;
          } else {
            const dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]];
            const [dc, dr] = dirs[Phaser.Math.Between(0, 3)];
            s.col = Phaser.Math.Clamp(s.col + dc, 0, COLS - 1);
            s.row = Phaser.Math.Clamp(s.row + dr, 0, ROWS - 1);
            s.rect.setPosition(s.col * 80 + 40, s.row * 80 + 40);
            s.stepMs = Phaser.Math.Between(250, 400);
          }
        }
      } else if (s.phase === 'fadeout') {
        s.rect.fillAlpha = Math.max(0, (1 - s.phaseTimer / FADE_OUT_MS)) * TARGET_ALPHA;
        if (s.phaseTimer >= FADE_OUT_MS) {
          s.rect.destroy();
          return false;
        }
      }
      return true;
    });
  }

  update(time, delta) {
    this.reticle?.update(delta);

    if (!this.player || this._frozen) return;

    this.player.update(delta);
    this.waveManager.update(delta);
    this.hud.update();

    this._checkBulletHits();
    this._checkEnemyProjectileHits();
    this._pruneEnemyProjectiles();
    this._updatePulseEffects(delta);
    this._updateShimmers(delta);

    if (this._waitingForExit) this._checkPlayerExit();
  }

  _updatePulseEffects(delta) {
    this._pulseEffects = this._pulseEffects.filter(effect => {
      effect.elapsed += delta;

      if (!effect.adjSpawned && effect.elapsed >= effect.ADJ_MS) {
        effect.adjSpawned = true;
        effect.adjacents.forEach(t => { if (t?.active) t.setVisible(true); });
      }

      if (effect.elapsed >= effect.FADE_MS) {
        const progress = Math.min(1, (effect.elapsed - effect.FADE_MS) / (effect.END_MS - effect.FADE_MS));
        if (effect.center?.active) effect.center.alpha = Math.max(0, 0.55 * (1 - progress));
        effect.adjacents.forEach(t => { if (t?.active) t.alpha = Math.max(0, 0.38 * (1 - progress)); });
      }

      if (effect.elapsed >= effect.END_MS) {
        if (effect.center?.active) effect.center.destroy();
        effect.adjacents.forEach(t => { if (t?.active) t.destroy(); });
        return false; // remove from array
      }
      return true;
    });
  }

  _checkBulletHits() {
    const bullets = this.player.bullets.getChildren();
    const enemies = this.waveManager.enemies;

    for (const bullet of bullets) {
      if (!bullet.active) continue;

      // Destroy bullet if it hits a barrier
      if (this.barrierManager.isPointBlocked(bullet.x, bullet.y)) {
        bullet.destroy();
        continue;
      }

      for (const enemy of enemies) {
        if (!enemy.active) continue;
        const dist = Phaser.Math.Distance.Between(bullet.x, bullet.y, enemy.x, enemy.y);
        if (dist < enemy.radius + 5) {
          enemy.takeDamage(bullet.damage);
          bullet.destroy();
          break;
        }
      }
    }
  }

  _checkEnemyProjectileHits() {
    this._enemyProjectiles = this._enemyProjectiles.filter(p => p?.active);
    this._enemyProjectiles.forEach(proj => {
      if (!proj.active) return;
      const dist = Phaser.Math.Distance.Between(proj.x, proj.y, this.player.x, this.player.y);
      if (dist < 16 + 6) {
        this.player.takeDamage(proj.damage);
        proj.destroy();
      }
    });
  }

  _pruneEnemyProjectiles() {
    this._enemyProjectiles = this._enemyProjectiles.filter(p => p?.active);
  }

  // ── Zone exit (Smash TV style) ─────────────────────────────────────────────

  _startZoneExit() {
    this.sound.play('sfx-edge-remove', { volume: 0.6 });
    // Explode edge barriers first, then allow exit
    this.barrierManager.explodeEdgeBarriers(() => {
      this._waitingForExit = true;
      this.player.sprite.body.setCollideWorldBounds(false);
      this._showExitArrows();
    });
  }

  _showExitArrows() {
    const W = this.scale.width;
    const H = this.scale.height;

    const g = this.add.graphics();
    g.setDepth(15);
    this._exitArrowsGfx = g;

    const ARROW_W = 30;   // triangle base half-width
    const ARROW_D = 28;   // triangle depth (pointing direction)
    const MARGIN = 18;   // gap from screen edge to arrow tip

    const drawUp = (cx, tipY) => g.fillTriangle(cx - ARROW_W, tipY + ARROW_D, cx + ARROW_W, tipY + ARROW_D, cx, tipY);
    const drawDown = (cx, tipY) => g.fillTriangle(cx - ARROW_W, tipY - ARROW_D, cx + ARROW_W, tipY - ARROW_D, cx, tipY);
    const drawLeft = (tipX, cy) => g.fillTriangle(tipX + ARROW_D, cy - ARROW_W, tipX + ARROW_D, cy + ARROW_W, tipX, cy);
    const drawRight = (tipX, cy) => g.fillTriangle(tipX - ARROW_D, cy - ARROW_W, tipX - ARROW_D, cy + ARROW_W, tipX, cy);

    // Three arrows per edge
    const xPositions = [W * 0.25, W * 0.5, W * 0.75];
    const yPositions = [H * 0.25, H * 0.5, H * 0.75];

    g.fillStyle(0xffffff, 1);
    xPositions.forEach(cx => {
      drawUp(cx, MARGIN);
      drawDown(cx, H - MARGIN);
    });
    yPositions.forEach(cy => {
      drawLeft(MARGIN, cy);
      drawRight(W - MARGIN, cy);
    });

    this._arrowPing = this.sound.add('sfx-arrow-ping', { loop: true, volume: 0.4 });
    this._arrowPing.play();

    // Blink the arrows
    this._exitArrowsTween = this.tweens.add({
      targets: g,
      alpha: 0.1,
      duration: 350,
      yoyo: true,
      repeat: -1,
      ease: 'Sine.easeInOut',
    });

    // "Zone cleared" prompt
    this._exitText = this.add.text(W / 2, 60, 'ZONE CLEARED  —  EXIT THROUGH ANY DOOR', {
      fontSize: '20px',
      fill: '#ffdd44',
      fontStyle: 'bold',
      stroke: '#000000',
      strokeThickness: 4,
    }).setOrigin(0.5).setDepth(15);

    this.tweens.add({
      targets: this._exitText,
      alpha: 0,
      duration: 400,
      yoyo: true,
      repeat: -1,
    });
  }

  _hideExitArrows() {
    this._exitArrowsTween?.stop();
    this._exitArrowsGfx?.destroy();
    this._exitText?.destroy();
    this._arrowPing?.stop();
    this._arrowPing = null;
    this._exitArrowsGfx = null;
    this._exitText = null;
  }

  _checkPlayerExit() {
    const W = this.scale.width;
    const H = this.scale.height;
    const px = this.player.x;
    const py = this.player.y;

    if (px < -24) this._doZoneTransition('left');
    else if (px > W + 24) this._doZoneTransition('right');
    else if (py < -24) this._doZoneTransition('top');
    else if (py > H + 24) this._doZoneTransition('bottom');
  }

  _doZoneTransition(direction) {
    this._waitingForExit = false;
    this._hideExitArrows();

    const W = this.scale.width;
    const H = this.scale.height;

    // Respawn player on the opposite edge, same lateral position
    const px = Phaser.Math.Clamp(this.player.x, 48, W - 48);
    const py = Phaser.Math.Clamp(this.player.y, 48, H - 48);
    const spawnX = direction === 'left' ? W - 48 : direction === 'right' ? 48 : px;
    const spawnY = direction === 'top' ? H - 48 : direction === 'bottom' ? 48 : py;

    // White flash
    const flash = this.add.rectangle(W / 2, H / 2, W, H, 0xffffff).setDepth(50);
    this.tweens.add({
      targets: flash,
      alpha: 0,
      duration: 300,
      onComplete: () => flash.destroy(),
    });

    this.player.sprite.setPosition(spawnX, spawnY);
    this.player.sprite.body.setCollideWorldBounds(true);
    this.waveManager.startNextZone();
    // Set up barriers AFTER zone index is incremented so we read the new zone's config
    if (this.waveManager.currentZone) this._setupBarriers();
    this._updateArenaColors(this.waveManager.zoneNum);
    this._shimmers.forEach(s => s.rect?.destroy());
    this._shimmers = [];
    this._shimmerTimer = 0;
    this._shimmerSpawnMs = 1500;
  }

  // ── Level up ───────────────────────────────────────────────────────────────

  _showLevelUp(level) {
    if (this._levelUpPending) return;
    this._levelUpPending = true;

    // Only show if there are skills available
    const available = this.skillTree.getAvailable();
    if (available.length === 0) {
      this._levelUpPending = false;
      return;
    }

    this._frozen = true;
    this.physics.world.pause();

    new SkillTreeUI(this, this.skillTree, this.player, () => {
      this._levelUpPending = false;
      this._frozen = false;
      this.physics.world.resume();
    });
  }

  _onGameOver() {
    this._bgMusic?.stop();
    this.scene.launch('GameOverScene');
    this.scene.pause();
  }

  _onVictory() {
    const W = this.scale.width;
    const H = this.scale.height;

    this.add.rectangle(W / 2, H / 2, W, H, 0x000000, 0.7).setDepth(30);
    this.add.text(W / 2, H / 2 - 40, 'VICTORY!', {
      fontFamily: 'FutureImperfect',
      fontSize: '72px', fill: '#ffdd00',
    }).setOrigin(0.5).setDepth(31);

    const prompt = this.add.text(W / 2, H / 2 + 60, 'Press R to return to menu', {
      fontSize: '22px', fill: '#ffffff'
    }).setOrigin(0.5).setDepth(31);
    this.tweens.add({ targets: prompt, alpha: 0, duration: 700, yoyo: true, repeat: -1 });

    this.input.keyboard.once('keydown-R', () => {
      this.scene.start('IntroScene');
    });
  }

  shutdown() {
    this.events.removeAllListeners();
    this._barrierColliders?.forEach(c => c.destroy());
    this.reticle?.destroy();
    this.barrierManager?.destroy();
    this._hideExitArrows();
    this._waitingForExit = false;
    this.player?.destroy();
    this.waveManager?.reset();
    this.hud?.destroy();
    this._bgMusic?.stop();
    this._bgMusic = null;
    this._enemyProjectiles = [];
    this._pulseEffects = [];
    this._shimmers?.forEach(s => s.rect?.destroy());
    this._shimmers = [];
  }
}
