/**
 * EnemyTank.js
 * Enemy tank with AI behavior: patrol, chase, and attack states.
 */

const Tank = require('./Tank');
const {
  TANK_TYPE,
  TANK_CONFIG,
  DIRECTION,
  DIR_VECTORS,
  GRID_COLS,
  GRID_ROWS,
  TILE_SIZE,
  MAP_OFFSET_X,
  MAP_OFFSET_Y,
} = require('../base/GameGlobal');

/** AI States */
const AI_STATE = {
  PATROL: 'patrol',
  CHASE: 'chase',
  ATTACK: 'attack',
};

class EnemyTank extends Tank {
  /**
   * @param {object} params
   * @param {string} params.type - TANK_TYPE enum value.
   * @param {number} params.col - Spawn grid column.
   * @param {number} params.row - Spawn grid row.
   * @param {number} [params.levelNum] - Current level number (affects AI).
   * @param {boolean} [params.hasPowerUp] - Whether destroying this tank drops a power-up.
   */
  constructor(params) {
    const cfg = TANK_CONFIG[params.type];
    const spawnX = MAP_OFFSET_X + params.col * TILE_SIZE + TILE_SIZE / 2;
    const spawnY = MAP_OFFSET_Y + params.row * TILE_SIZE + TILE_SIZE / 2;
    const speedMul = params.speedMultiplier || 1;

    super({
      x: spawnX,
      y: spawnY,
      speed: cfg.speed * speedMul,
      hp: cfg.hp,
      color: cfg.color,
      size: cfg.size,
      colliderSize: cfg.colliderSize || cfg.size,
      direction: DIRECTION.DOWN,
    });

    this.type = params.type;
    this.score = cfg.score || 100;
    this.hasPowerUp = params.hasPowerUp || false;
    this.levelNum = params.levelNum || 1;

    // AI state
    this._aiState = AI_STATE.PATROL;
    this._moveTimer = 0;
    this._dirChangeInterval = 1.5 + Math.random() * 2; // seconds
    this._shootTimer = 0;
    this._shootInterval = 1 + Math.random() * 1.5; // seconds
    this._stuckTimer = 0;
    this._lastX = spawnX;
    this._lastY = spawnY;

    // Frozen state (from clock power-up)
    this.frozen = false;

    // Active bullets tracking
    this.activeBullets = 0;
    this._maxBullets = params.type === TANK_TYPE.ENEMY_BOSS ? 2 : 1;

    // HP indicator blink for armored tanks
    this._hitBlink = 0;
  }

  /**
   * Update enemy tank AI and state.
   * @param {number} dt - Delta time in seconds.
   * @param {MapManager} mapManager
   * @param {{x: number, y: number}} basePos - Base position for targeting.
   * @param {Function} onShoot - Callback to fire a bullet.
   */
  update(dt, mapManager, basePos, onShoot) {
    if (!this.alive || this.frozen) return;

    // Hit blink effect
    if (this._hitBlink > 0) {
      this._hitBlink -= dt;
    }

    // Movement AI
    this._moveTimer += dt;
    this._shootTimer += dt;

    // Check if stuck
    const moved = Math.abs(this.x - this._lastX) + Math.abs(this.y - this._lastY);
    if (moved < 0.5) {
      this._stuckTimer += dt;
    } else {
      this._stuckTimer = 0;
    }
    this._lastX = this.x;
    this._lastY = this.y;

    // Determine AI behavior based on level
    if (this.levelNum >= 10 && this.type !== TANK_TYPE.ENEMY_NORMAL) {
      this._aiState = AI_STATE.CHASE;
    } else if (Math.random() < 0.3) {
      this._aiState = AI_STATE.CHASE;
    } else {
      this._aiState = AI_STATE.PATROL;
    }

    // Direction change
    if (this._moveTimer >= this._dirChangeInterval || this._stuckTimer > 0.5) {
      this._moveTimer = 0;
      this._stuckTimer = 0;
      this._chooseDirection(mapManager, basePos);
    }

    // Move
    this.move(this.direction, dt, mapManager);

    // Shoot
    if (this._shootTimer >= this._shootInterval) {
      this._shootTimer = 0;
      this._shootInterval = 0.8 + Math.random() * 1.5;

      if (this.activeBullets < this._maxBullets && onShoot) {
        onShoot(this);
      }
    }
  }

  /**
   * Choose a new direction based on AI state.
   * @private
   */
  _chooseDirection(mapManager, basePos) {
    if (this._aiState === AI_STATE.CHASE && basePos) {
      // Move towards base
      this._chaseTarget(basePos, mapManager);
    } else {
      // Random patrol
      this._randomDirection(mapManager);
    }
  }

  /**
   * Chase a target position (usually the base).
   * @private
   */
  _chaseTarget(target, mapManager) {
    const dx = target.x - this.x;
    const dy = target.y - this.y;

    // Prefer the axis with greater distance
    const dirs = [];
    if (Math.abs(dy) > Math.abs(dx)) {
      dirs.push(dy > 0 ? DIRECTION.DOWN : DIRECTION.UP);
      dirs.push(dx > 0 ? DIRECTION.RIGHT : DIRECTION.LEFT);
    } else {
      dirs.push(dx > 0 ? DIRECTION.RIGHT : DIRECTION.LEFT);
      dirs.push(dy > 0 ? DIRECTION.DOWN : DIRECTION.UP);
    }

    // Add random alternatives for variety
    const allDirs = [DIRECTION.UP, DIRECTION.DOWN, DIRECTION.LEFT, DIRECTION.RIGHT];
    for (const d of allDirs) {
      if (!dirs.includes(d)) dirs.push(d);
    }

    // Try each direction, pick the first that isn't immediately blocked
    for (const dir of dirs) {
      const vec = DIR_VECTORS[dir];
      const testX = this.x + vec.dx * TILE_SIZE;
      const testY = this.y + vec.dy * TILE_SIZE;
      const left = testX - this.colliderHalfSize;
      const top = testY - this.colliderHalfSize;

      if (!mapManager.rectCollidesWithTerrain(left, top, this.colliderSize, this.colliderSize)) {
        this.direction = dir;
        return;
      }
    }

    // Fallback: random
    this.direction = allDirs[Math.floor(Math.random() * allDirs.length)];
  }

  /**
   * Choose a random direction.
   * @private
   */
  _randomDirection(mapManager) {
    const dirs = [DIRECTION.UP, DIRECTION.DOWN, DIRECTION.LEFT, DIRECTION.RIGHT];
    // Bias towards down (towards base) 40% of the time
    if (Math.random() < 0.4) {
      this.direction = DIRECTION.DOWN;
      return;
    }
    this.direction = dirs[Math.floor(Math.random() * dirs.length)];
  }

  /**
   * Override takeDamage to add hit blink.
   */
  takeDamage(amount = 1) {
    this._hitBlink = 0.15;
    return super.takeDamage(amount);
  }

  /**
   * Render with HP indicator for armored tanks.
   * @param {CanvasRenderingContext2D} ctx
   */
  render(ctx) {
    if (!this.alive) return;

    // Hit blink effect
    if (this._hitBlink > 0) {
      ctx.save();
      ctx.globalAlpha = 0.5;
      super.render(ctx);
      ctx.restore();
    } else {
      super.render(ctx);
    }

    // Power-up indicator (flashing border)
    if (this.hasPowerUp) {
      ctx.save();
      ctx.strokeStyle = '#FF0000';
      ctx.lineWidth = 2;
      const blink = Math.sin(Date.now() / 150) > 0;
      if (blink) {
        ctx.strokeRect(
          this.x - this.halfSize - 2,
          this.y - this.halfSize - 2,
          this.size + 4,
          this.size + 4
        );
      }
      ctx.restore();
    }

    // HP bar for armored/boss tanks
    if (this.maxHp > 1) {
      const barW = this.size;
      const barH = 3;
      const barX = this.x - this.halfSize;
      const barY = this.y - this.halfSize - 6;

      ctx.fillStyle = '#333333';
      ctx.fillRect(barX, barY, barW, barH);

      ctx.fillStyle = this.hp > this.maxHp * 0.3 ? '#00FF00' : '#FF0000';
      ctx.fillRect(barX, barY, barW * (this.hp / this.maxHp), barH);
    }
  }

  /** Whether this enemy can fire. */
  canFire() {
    return this.alive && !this.frozen && this.activeBullets < this._maxBullets;
  }
}

module.exports = EnemyTank;
