/**
 * @typedef {import("../grid/VoxelGrid.js").VoxelGrid} VoxelGrid
 * @typedef {import("../grid/types.js").VoxelId} VoxelId
 */

import { SeededRandom } from "../utils/SeededRandom.js";

/**
 * Base class for world generators.
 * @class
 */
export class BaseGenerator {
  /**
   * @param {VoxelGrid} grid - Voxel grid to generate into
   * @param {number} seed - Random seed
   */
  constructor(grid, seed) {
    /** @type {VoxelGrid} */
    this.grid = grid;
    /** @type {SeededRandom} */
    this.rng = new SeededRandom(seed);
    /** @type {number} */
    this.width = grid.size.x;
    /** @type {number} */
    this.height = grid.size.y;
    /** @type {number} */
    this.depth = grid.size.z;
  }

  /**
   * Counts solid neighbors around a position.
   * @param {number} x - X coordinate
   * @param {number} y - Y coordinate
   * @param {number} z - Z coordinate
   * @returns {number} - Number of solid neighbors
   */
  getSolidNeighbors(x, y, z) {
    let count = 0;
    for (let i = -1; i <= 1; i++) {
      for (let j = -1; j <= 1; j++) {
        for (let k = -1; k <= 1; k++) {
          if (i === 0 && j === 0 && k === 0) continue;
          if (
            !this.grid.isValidBounds(x + i, y + j, z + k) ||
            this.grid.isSolid({ x: x + i, y: y + j, z: z + k })
          ) {
            count++;
          }
        }
      }
    }
    return count;
  }

  /**
   * Spreads destructible objects across valid floor tiles.
   * @param {number} objectId - The Voxel ID for the cover (e.g., 10 for Wood).
   * @param {number} density - 0.0 to 1.0 (e.g., 0.1 for 10% coverage).
   */
  scatterCover(objectId, density) {
    const validSpots = [];

    // 1. Identify all valid "Floor" surfaces (Solid below, Air current)
    for (let x = 1; x < this.width - 1; x++) {
      for (let z = 1; z < this.depth - 1; z++) {
        for (let y = 1; y < this.height - 1; y++) {
          const currentId = this.grid.getCell(x, y, z);
          const belowId = this.grid.getCell(x, y - 1, z);

          if (currentId === 0 && belowId !== 0) {
            validSpots.push({ x, y, z });
          }
        }
      }
    }

    // 2. Place objects based on density
    for (const pos of validSpots) {
      if (this.rng.chance(density)) {
        this.grid.setCell(pos.x, pos.y, pos.z, objectId);
      }
    }
  }
}
