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

import { BaseGenerator } from "./BaseGenerator.js";
// We can reuse the texture generators or create specific Ruin ones.
import { RustedWallTextureGenerator } from "./textures/RustedWallTextureGenerator.js";
import { RustedFloorTextureGenerator } from "./textures/RustedFloorTextureGenerator.js";

/**
 * Generates structured rooms and corridors.
 * Uses an "Additive" approach (Building in Void) to ensure good visibility.
 * Integrated with Procedural Texture Palette.
 * @class
 */
export class RuinGenerator extends BaseGenerator {
  /**
   * @param {import("../grid/VoxelGrid.js").VoxelGrid} grid - Voxel grid to generate into
   * @param {number} seed - Random seed
   */
  constructor(grid, seed) {
    super(grid, seed);

    // Use Rusted Floor for the Industrial aesthetic
    /** @type {RustedFloorTextureGenerator} */
    this.floorGen = new RustedFloorTextureGenerator(seed);
    /** @type {RustedWallTextureGenerator} */
    this.wallGen = new RustedWallTextureGenerator(seed);

    /** @type {GeneratedAssets} */
    this.generatedAssets = {
      palette: {},
      // New: Explicitly track valid spawn locations for teams
      spawnZones: {
        player: [],
        enemy: [],
      },
    };

    this.preloadTextures();
  }

  /**
   * Preloads texture variations.
   * @private
   */
  preloadTextures() {
    const VARIATIONS = 10;
    const TEXTURE_SIZE = 128;

    // 1. Preload Wall Variations (IDs 100 - 109)
    for (let i = 0; i < VARIATIONS; i++) {
      const wallSeed = this.rng.next() * 5000 + i;
      const tempWallGen = new RustedWallTextureGenerator(wallSeed);
      this.generatedAssets.palette[100 + i] =
        tempWallGen.generateWall(TEXTURE_SIZE);
    }

    // 2. Preload Floor Variations (IDs 200 - 209)
    for (let i = 0; i < VARIATIONS; i++) {
      const floorSeed = this.rng.next() * 10000 + i;
      this.generatedAssets.palette[200 + i] = this.floorGen.generateFloor(
        TEXTURE_SIZE,
        floorSeed
      );
    }
  }

  generate(roomCount = 5, minSize = 4, maxSize = 8) {
    // Start with Empty Air (0)
    this.grid.fill(0);

    const rooms = [];

    // 1. Place Rooms
    for (let i = 0; i < 50; i++) {
      if (rooms.length >= roomCount) break;

      const w = this.rng.rangeInt(minSize, maxSize);
      const d = this.rng.rangeInt(minSize, maxSize);
      const x = this.rng.rangeInt(1, this.width - w - 2);
      const z = this.rng.rangeInt(1, this.depth - d - 2);
      const y = 1; // Main floor level

      const room = { x, y, z, w, d };

      if (!this.roomsOverlap(room, rooms)) {
        this.buildRoom(room); // Additive building
        rooms.push(room);
      }
    }

    // 2. Connect Rooms
    for (let i = 1; i < rooms.length; i++) {
      const prev = this.getCenter(rooms[i - 1]);
      const curr = this.getCenter(rooms[i]);
      this.buildCorridor(prev, curr); // Additive building
    }

    // 3. Define Spawn Zones
    // Player gets the first room, Enemy gets the last room
    if (rooms.length > 0) {
      this.markSpawnZone(rooms[0], "player");
      this.markSpawnZone(rooms[rooms.length - 1], "enemy");
    }

    // 3. Apply Texture/Material Logic
    this.applyTextures();

    // 4. Scatter Cover (Post-Texturing)
    // ID 10 = Scrap/Crates
    // 10% Density for Ruins (More cover than caves)
    this.scatterCover(10, 0.1);
  }

  /**
   * Collects valid floor tiles from a room and adds them to a spawn zone.
   */
  markSpawnZone(room, type) {
    // Scan the room's interior (excluding walls)
    // We assume y=1 is the walking surface
    for (let x = room.x + 1; x < room.x + room.w - 1; x++) {
      for (let z = room.z + 1; z < room.z + room.d - 1; z++) {
        // Double check it's a valid floor (Solid at 0, Air at 1)
        // Note: IDs haven't been textured yet, so floor is still ID 1
        if (
          this.grid.getCell(x, 0, z) !== 0 &&
          this.grid.getCell(x, 1, z) === 0
        ) {
          this.generatedAssets.spawnZones[type].push({ x, y: 1, z });
        }
      }
    }
  }

  roomsOverlap(room, rooms) {
    for (const r of rooms) {
      if (
        room.x < r.x + r.w &&
        room.x + room.w > r.x &&
        room.z < r.z + r.d &&
        room.z + room.d > r.z
      ) {
        return true;
      }
    }
    return false;
  }

  getCenter(room) {
    return {
      x: Math.floor(room.x + room.w / 2),
      y: room.y,
      z: Math.floor(room.z + room.d / 2),
    };
  }

  buildRoom(r) {
    for (let x = r.x; x < r.x + r.w; x++) {
      for (let z = r.z; z < r.z + r.d; z++) {
        // 1. Build Floor Foundation (y=0) - Placeholder ID 1
        this.grid.setCell(x, r.y - 1, z, 1);

        // 2. Determine if this is a Wall (Perimeter) or Interior
        const isWall =
          x === r.x || x === r.x + r.w - 1 || z === r.z || z === r.z + r.d - 1;

        if (isWall) {
          this.grid.setCell(x, r.y, z, 1); // Wall Base
          this.grid.setCell(x, r.y + 1, z, 1); // Wall Top
        } else {
          this.grid.setCell(x, r.y, z, 0);
          this.grid.setCell(x, r.y + 1, z, 0);
        }
      }
    }
  }

  buildCorridor(start, end) {
    const stepX = Math.sign(end.x - start.x);
    let currX = start.x;
    while (currX !== end.x) {
      this.buildPathPoint(currX, start.y, start.z);
      currX += stepX;
    }

    const stepZ = Math.sign(end.z - start.z);
    let currZ = start.z;
    while (currZ !== end.z) {
      this.buildPathPoint(end.x, start.y, currZ);
      currZ += stepZ;
    }
  }

  buildPathPoint(x, y, z) {
    this.grid.setCell(x, y - 1, z, 1);
    this.grid.setCell(x, y, z, 0);
    this.grid.setCell(x, y + 1, z, 0);
  }

  applyTextures() {
    for (let x = 0; x < this.width; x++) {
      for (let z = 0; z < this.depth; z++) {
        for (let y = 0; y < this.height; y++) {
          const current = this.grid.getCell(x, y, z);
          const above = this.grid.getCell(x, y + 1, z);

          if (current !== 0) {
            if (above === 0) {
              const variant = this.rng.rangeInt(0, 9);
              this.grid.setCell(x, y, z, 200 + variant);
            } else {
              const variant = this.rng.rangeInt(0, 9);
              this.grid.setCell(x, y, z, 100 + variant);
            }
          }
        }
      }
    }
  }
}
