const TURN_RATE_DEG = 4;       // degrees per frame at 60fps
const BULLET_SPEED = 700;
const BULLET_DAMAGE = 20;
const BULLET_SIZE = 5;
const PLAYER_RADIUS = 16;
// Sprite faces DOWN at rotation=0; Phaser's 0° is RIGHT, so offset by -90°
const SPRITE_ROTATION_OFFSET = -Math.PI / 2;
// Gun tip distance from sprite center (in pixels)
const GUN_TIP_DIST = 24;

export class Player {
  constructor(scene, x, y) {
    this.scene = scene;
    this.facing = 0; // radians

    // Mutable stat block — modified by skill tree
    this.stats = {
      speed: 200,
      damage: BULLET_DAMAGE,
      fireRate: 1,        // multiplier applied to cooldown
      damageReduction: 0, // 0–1 additive
      maxHp: 100,
    };

    this.hp = this.stats.maxHp;
    this.lives = 3;
    this.invincible = false;
    this._dead = false;
    this._fireCooldown = 0;
    this._baseFireInterval = 250; // ms between shots
    this._isMoving = false;
    this._isShooting = false;

    this._createAnims();
    this._buildSprite(x, y);
    this._setupKeys();
    this.bullets = scene.add.group();
  }

  _createAnims() {
    const anims = this.scene.anims;
    if (anims.exists('player-idle')) return; // already created

    anims.create({ key: 'player-idle', frames: [{ key: 'player', frame: 0 }], frameRate: 1, repeat: -1 });
    anims.create({ key: 'player-walk', frames: anims.generateFrameNumbers('player', { frames: [1, 2] }), frameRate: 8, repeat: -1 });
    anims.create({ key: 'player-idle-gun', frames: [{ key: 'player', frame: 3 }], frameRate: 1, repeat: -1 });
    anims.create({ key: 'player-walk-gun', frames: anims.generateFrameNumbers('player', { frames: [4, 5] }), frameRate: 8, repeat: -1 });
  }

  _buildSprite(x, y) {
    this.sprite = this.scene.add.sprite(x, y, 'player').setDepth(6);
    this.scene.physics.add.existing(this.sprite);
    this.sprite.body.setCollideWorldBounds(true);
    // Circle hitbox centered in the 48×48 sprite: radius 16, offset 8 from top-left
    this.sprite.body.setCircle(PLAYER_RADIUS, 8, 8);
    this.sprite.play('player-idle');
  }

  _setupKeys() {
    this.keys = this.scene.input.keyboard.addKeys({
      up: Phaser.Input.Keyboard.KeyCodes.W,
      down: Phaser.Input.Keyboard.KeyCodes.S,
      left: Phaser.Input.Keyboard.KeyCodes.A,
      right: Phaser.Input.Keyboard.KeyCodes.D,
    });
  }

  get x() { return this.sprite.x; }
  get y() { return this.sprite.y; }
  get active() { return this.sprite?.active ?? false; }

  update(delta) {
    if (this._dead) return;
    this._move();
    this._rotateFacing(delta);
    this._handleFire(delta);
    this._updateAnimation();
    this._updateBullets();
  }

  _move() {
    let dx = 0, dy = 0;
    if (this.keys.left.isDown) dx -= 1;
    if (this.keys.right.isDown) dx += 1;
    if (this.keys.up.isDown) dy -= 1;
    if (this.keys.down.isDown) dy += 1;

    this._isMoving = dx !== 0 || dy !== 0;
    if (dx !== 0 && dy !== 0) { dx *= 0.707; dy *= 0.707; }
    this.sprite.body.setVelocity(dx * this.stats.speed, dy * this.stats.speed);
  }

  _rotateFacing(delta) {
    const ptr = this.scene.input.activePointer;
    const targetAngle = Phaser.Math.Angle.Between(this.x, this.y, ptr.worldX, ptr.worldY);
    const maxTurn = Phaser.Math.DegToRad(TURN_RATE_DEG) * (delta / (1000 / 60));
    this.facing = Phaser.Math.Angle.RotateTo(this.facing, targetAngle, maxTurn);
    // Sprite art faces DOWN; offset by -90° so it faces RIGHT at facing=0
    this.sprite.setRotation(this.facing + SPRITE_ROTATION_OFFSET);
  }

  _handleFire(delta) {
    this._fireCooldown -= delta;
    const ptr = this.scene.input.activePointer;
    this._isShooting = ptr.isDown;
    if (ptr.isDown && this._fireCooldown <= 0) {
      this._fireCooldown = this._baseFireInterval / this.stats.fireRate;
      this._spawnBullet();
    }
  }

  _updateAnimation() {
    let key;
    if (this._isMoving && this._isShooting) key = 'player-walk-gun';
    else if (this._isMoving) key = 'player-walk';
    else if (this._isShooting) key = 'player-idle-gun';
    else key = 'player-idle';

    if (this.sprite.anims.currentAnim?.key !== key) {
      this.sprite.play(key);
    }
  }

  _spawnBullet() {
    this.scene.sound.play('sfx-shoot', { volume: 0.4 });
    const bx = this.x + Math.cos(this.facing) * GUN_TIP_DIST;
    const by = this.y + Math.sin(this.facing) * GUN_TIP_DIST;
    const bullet = this.scene.add.circle(bx, by, BULLET_SIZE, 0xffff00);
    this.scene.physics.add.existing(bullet);
    bullet.body.setVelocity(
      Math.cos(this.facing) * BULLET_SPEED,
      Math.sin(this.facing) * BULLET_SPEED
    );
    bullet.damage = this.stats.damage;
    this.bullets.add(bullet);
  }

  _updateBullets() {
    const W = this.scene.scale.width;
    const H = this.scene.scale.height;
    this.bullets.getChildren().forEach(b => {
      if (b.x < -20 || b.x > W + 20 || b.y < -20 || b.y > H + 20) {
        b.destroy();
      }
    });
  }

  takeDamage(amount) {
    if (this.invincible) return;
    const reduced = amount * (1 - Math.min(this.stats.damageReduction, 0.9));
    this.hp -= reduced;

    if (this.hp <= 0) {
      this.hp = 0;
      this._hitFlash(true);
      this._loseLife();
    } else {
      this._hitFlash(false);
    }
  }

  _hitFlash(isLifeLost) {
    this.scene.sound.play('sfx-take-damage', { volume: 0.5 });
    const scene = this.scene;
    const W = scene.scale.width;
    const H = scene.scale.height;

    scene.cameras.main.shake(isLifeLost ? 300 : 80, isLifeLost ? 0.016 : 0.005);

    const alpha = isLifeLost ? 0.55 : 0.28;
    const duration = isLifeLost ? 400 : 220;
    const flash = scene.add.rectangle(W / 2, H / 2, W, H, 0xff0000, alpha).setDepth(49);
    scene.tweens.add({ targets: flash, alpha: 0, duration, onComplete: () => flash.destroy() });

    if (!isLifeLost) {
      this.sprite.setTint(0xff4444);
      scene.time.delayedCall(100, () => { if (this.sprite?.active) this.sprite.clearTint(); });
    }
  }

  _loseLife() {
    const livesBeforeDeath = this.lives;
    this.lives--;

    if (this.lives <= 0) {
      this.scene.events.emit('game-over');
      return;
    }

    this.scene.sound.play('sfx-death', { volume: 0.6 });

    this.hp = this.stats.maxHp;
    this.invincible = true;
    this._dead = true;
    this.sprite.body.setVelocity(0, 0);
    this.sprite.anims.stop();

    // Spin and fade out
    this.scene.tweens.add({
      targets: this.sprite,
      angle: '+=720',
      alpha: 0,
      duration: 600,
      ease: 'Power2',
      onComplete: () => {
        const W = this.scene.scale.width;
        const H = this.scene.scale.height;
        this.sprite.setPosition(W / 2, H / 2);
        this.sprite.setAngle(0);
        this.sprite.setAlpha(1);
        this._dead = false;
        this.scene.sound.play('sfx-new-life', { volume: 0.6 });
        this._startInvincibility();
      },
    });

    this._showLivesOverlay(livesBeforeDeath, this.lives);
  }

  _startInvincibility() {
    this.invincible = true;
    // Blink for ~5 seconds: 17 cycles × 300ms = 5.1s
    this.scene.tweens.add({
      targets: this.sprite,
      alpha: 0,
      duration: 150,
      yoyo: true,
      repeat: 16,
      onComplete: () => {
        this.sprite.setAlpha(1);
        this.invincible = false;
      },
    });
  }

  _showLivesOverlay(oldLives, newLives) {
    const scene = this.scene;
    const W = scene.scale.width;
    const H = scene.scale.height;
    const cx = W / 2;
    const cy = H * 0.3;

    const baseStyle = {
      fontFamily: 'FutureImperfect',
      fontSize: '52px',
      stroke: '#000000', strokeThickness: 6,
    };

    const label = scene.add.text(cx, cy, 'Lives: ', { ...baseStyle, fill: '#ffffff' })
      .setOrigin(1, 0.5).setDepth(60);
    const oldText = scene.add.text(cx, cy, String(oldLives), { ...baseStyle, fill: '#ff4444' })
      .setOrigin(0, 0.5).setDepth(60);

    // Shake old count, then fade it out, then show new count
    scene.tweens.add({
      targets: oldText,
      x: oldText.x + 12,
      duration: 50,
      yoyo: true,
      repeat: 7,
      delay: 400,
      onComplete: () => {
        scene.tweens.add({
          targets: oldText,
          alpha: 0,
          duration: 180,
          onComplete: () => {
            oldText.destroy();
            const newText = scene.add.text(cx, cy, String(newLives), { ...baseStyle, fill: '#44ff88' })
              .setOrigin(0, 0.5).setDepth(60).setAlpha(0);
            scene.tweens.add({
              targets: newText,
              alpha: 1,
              duration: 200,
              onComplete: () => {
                scene.time.delayedCall(900, () => {
                  scene.tweens.add({
                    targets: [label, newText],
                    alpha: 0,
                    duration: 1200,
                    onComplete: () => { label.destroy(); newText.destroy(); },
                  });
                });
              },
            });
          },
        });
      },
    });
  }

  respawn(x, y) {
    this.sprite.setPosition(x, y);
    this.hp = this.stats.maxHp;
    this._startInvincibility();
  }

  destroy() {
    this.sprite.destroy();
    this.bullets.clear(true, true);
  }
}
