// spatialGrid.ts
import type { SpatialGrid, GridCell, Enemy, Vector, GameConfig } from "./types"

export class SpatialGridSystem implements SpatialGrid {
  public cells: GridCell[][] = []
  public cellSize: number = 0
  public cols: number = 0
  public rows: number = 0

  constructor(config: GameConfig) {
    this.cellSize = config.grid.cellSize
    this.cols = config.grid.cols
    this.rows = config.grid.rows

    // Initialize grid
    this.cells = []
    for (let y = 0; y < this.rows; y++) {
      this.cells[y] = []
      for (let x = 0; x < this.cols; x++) {
        this.cells[y][x] = { enemies: [] }
      }
    }
  }

  private getGridCoords(
    x: number,
    y: number,
  ): { gridX: number; gridY: number } {
    return {
      gridX: Math.max(
        0,
        Math.min(this.cols - 1, Math.floor(x / this.cellSize)),
      ),
      gridY: Math.max(
        0,
        Math.min(this.rows - 1, Math.floor(y / this.cellSize)),
      ),
    }
  }

  clear(): void {
    for (let y = 0; y < this.rows; y++) {
      for (let x = 0; x < this.cols; x++) {
        this.cells[y][x].enemies.length = 0
      }
    }
  }

  addEnemy(enemy: Enemy): void {
    const bounds = enemy.bounds
    const centerX = bounds.left + bounds.width / 2
    const centerY = bounds.top + bounds.height / 2

    const { gridX, gridY } = this.getGridCoords(centerX, centerY)

    enemy.gridX = gridX
    enemy.gridY = gridY

    if (this.cells[gridY] && this.cells[gridY][gridX]) {
      this.cells[gridY][gridX].enemies.push(enemy)
    }
  }

  getEnemiesNearPoint(point: Vector, radius: number = 0): Enemy[] {
    const enemies: Enemy[] = []
    const radiusInCells = Math.ceil(radius / this.cellSize)

    const { gridX, gridY } = this.getGridCoords(point.x, point.y)

    const minX = Math.max(0, gridX - radiusInCells)
    const maxX = Math.min(this.cols - 1, gridX + radiusInCells)
    const minY = Math.max(0, gridY - radiusInCells)
    const maxY = Math.min(this.rows - 1, gridY + radiusInCells)

    for (let y = minY; y <= maxY; y++) {
      for (let x = minX; x <= maxX; x++) {
        if (this.cells[y] && this.cells[y][x]) {
          enemies.push(...this.cells[y][x].enemies)
        }
      }
    }

    return enemies
  }

  getAllEnemies(): Enemy[] {
    const enemies: Enemy[] = []
    for (let y = 0; y < this.rows; y++) {
      for (let x = 0; x < this.cols; x++) {
        if (this.cells[y] && this.cells[y][x]) {
          enemies.push(...this.cells[y][x].enemies)
        }
      }
    }
    return enemies
  }

  removeEnemy(enemy: Enemy): void {
    if (this.cells[enemy.gridY] && this.cells[enemy.gridY][enemy.gridX]) {
      const cell = this.cells[enemy.gridY][enemy.gridX]
      const index = cell.enemies.indexOf(enemy)
      if (index > -1) {
        cell.enemies.splice(index, 1)
      }
    }
  }
}
