import { BaseGenerator } from "./BaseGenerator.js";
import { VoidSeepTextureGenerator } from "./textures/VoidSeepTextureGenerator.js";

/**
 * Generates the "Void Seep Depths" biome.
 * Structure: Circular Arena with "Void Rifts" (Holes) and corruption.
 * IDs:
 *  - 50: Obsidian Floor
 *  - 51: Corruption Vein (Floor)
 *  - 52: Obsidian Pillar (Wall/Obstacle)
 *  - 55: Pulsing Tumor (Cover)
 */
export class VoidSeepDepthsGenerator extends BaseGenerator {
  constructor(grid, seed) {
    super(grid, seed);
    this.generatedAssets = {
      palette: {},
      spawnZones: { player: [], enemy: [] },
    };
    this.preloadAssets();
  }

  preloadAssets() {
    if (typeof OffscreenCanvas === "undefined") {
      console.warn(
        "OffscreenCanvas not available. Skipping texture generation."
      );
      return;
    }
    const texGen = new VoidSeepTextureGenerator(this.seed);

    // ID 50: Obsidian Floor
    this.generatedAssets.palette[50] = texGen.generateObsidian(64);

    // ID 51: Corruption Vein (Hot pink/Purple)
    this.generatedAssets.palette[51] = texGen.generateCorruption(64);

    // ID 52: Obsidian Pillar (Same as floor but vertical usage)
    this.generatedAssets.palette[52] = this.generatedAssets.palette[50]; // Reuse obsidian

    // ID 53: Glowing Obsidian Pillar (Obsidian with Veins)
    // Reuse corruption texture for strong glow
    this.generatedAssets.palette[53] = this.generatedAssets.palette[51];

    // ID 55: Pulsing Tumor (Organic/Gross)
    // Reuse corruption for now or tweak
    this.generatedAssets.palette[55] = texGen.generateCorruption(64);
  }

  /**
   * Generates the level.
   * @param {number} difficulty - affecting hazard density
   */
  generate(difficulty = 1) {
    this.grid.fill(0); // Sky

    const cx = Math.floor(this.width / 2);
    const cz = Math.floor(this.depth / 2);
    const arenaRadius = Math.min(cx, cz) - 2;
    const floorY = 5;

    // 1. Build Base Arena (Obsidian Disc)
    this.buildDisc(cx, floorY, cz, arenaRadius, 50);

    // 2. Carve Void Rifts (Holes)
    // Avoid Center and "Safe Zones" (North/South spawn points)
    const riftCount = 5 + difficulty * 2;
    for (let i = 0; i < riftCount; i++) {
      const angle = this.rng.next() * Math.PI * 2;
      const r = this.rng.range(5, arenaRadius - 2); // Avoid very edge
      const rx = Math.floor(cx + Math.cos(angle) * r);
      const rz = Math.floor(cz + Math.sin(angle) * r);

      // CHECK SAFE ZONES
      // Safe Zone 1: North (Z min)
      if (this.dist2D(rx, rz, cx, 2) < 6) continue;
      // Safe Zone 2: South (Z max)
      if (this.dist2D(rx, rz, cx, this.depth - 2) < 6) continue;
      // Center Safe Zone (optional, good for king of hill)
      if (this.dist2D(rx, rz, cx, cz) < 5) continue;

      const radius = this.rng.rangeInt(2, 4);
      this.carveCylinder(rx, floorY - 1, rz, radius, 3, 0); // Carve air (0)
    }

    // 3. Corruption Veins
    // Replace some floor with corruption
    this.scatterVeins(51, 0.1); // 10% corruption

    // 4. Vertical Cover (Obsidian Spikes)
    const pillarCount = 8;
    for (let i = 0; i < pillarCount; i++) {
      const angle = this.rng.next() * Math.PI * 2;
      const r = this.rng.range(5, arenaRadius - 3);
      const px = Math.floor(cx + Math.cos(angle) * r);
      const pz = Math.floor(cz + Math.sin(angle) * r);

      // Avoid void (don't build on air)
      if (this.grid.getCell(px, floorY, pz) === 0) continue;

      const h = this.rng.rangeInt(3, 8);
      // 30% Chance to be a "Glowing Pillar" (ID 53)
      const pId = this.rng.chance(0.3) ? 53 : 52;
      this.buildPillar(px, floorY, pz, h, pId);
    }

    // 5. Scatter Tumors (Low Cover)
    this.scatterCover(55, 0.05); // 5% density on valid floor

    // 6. Define Spawn Zones
    // Player: North (Z min), Enemy: South (Z max)
    // We scan the "Safe Zones" we protected from rifts earlier.
    const safeRadius = 6;

    // Player Zone (North: cz - r to cz - r + safe) -> Wait, Z=0 is North?
    // In generate(): Safe Zone 1: North (Z min) -> check (cx, 2)
    // Safe Zone 2: South (Z max) -> check (cx, depth-2)

    this.markSafeZoneSpawn(cx, 2, safeRadius, "player");
    this.markSafeZoneSpawn(cx, this.depth - 2, safeRadius, "enemy");
  }

  markSafeZoneSpawn(cx, cz, r, type) {
    for (let x = cx - r; x <= cx + r; x++) {
      for (let z = cz - r; z <= cz + r; z++) {
        if (this.dist2D(x, z, cx, cz) <= r) {
          // Check if valid floor (ID 50/51/etc) and Air above
          // Floor is at y=5
          const fy = 5;
          if (
            this.grid.isValidBounds(x, fy, z) &&
            this.grid.getCell(x, fy, z) !== 0 &&
            this.grid.getCell(x, fy + 1, z) === 0
          ) {
            this.generatedAssets.spawnZones[type].push({ x, y: fy + 1, z });
          }
        }
      }
    }
  }

  buildDisc(cx, y, cz, r, id) {
    for (let x = cx - r; x <= cx + r; x++) {
      for (let z = cz - r; z <= cz + r; z++) {
        if (this.dist2D(x, z, cx, cz) <= r) {
          // Make it 2 blocks thick
          this.grid.setCell(x, y, z, id);
          this.grid.setCell(x, y - 1, z, id);
        }
      }
    }
  }

  carveCylinder(cx, bottomY, cz, r, height, id) {
    for (let y = bottomY; y < bottomY + height; y++) {
      for (let x = cx - r; x <= cx + r; x++) {
        for (let z = cz - r; z <= cz + r; z++) {
          if (this.dist2D(x, z, cx, cz) <= r) {
            if (this.grid.isValidBounds(x, y, z)) {
              this.grid.setCell(x, y, z, id);
            }
          }
        }
      }
    }
  }

  buildPillar(cx, bottomY, cz, height, id) {
    // Simple 1x1 or cross
    for (let y = bottomY + 1; y <= bottomY + height; y++) {
      this.grid.setCell(cx, y, cz, id);
      // Make base slightly thicker
      if (y === bottomY + 1) {
        this.grid.setCell(cx + 1, y, cz, id);
        this.grid.setCell(cx - 1, y, cz, id);
        this.grid.setCell(cx, y, cz + 1, id);
        this.grid.setCell(cx, y, cz - 1, id);
      }
    }
  }

  scatterVeins(id, density) {
    for (let x = 0; x < this.width; x++) {
      for (let z = 0; z < this.depth; z++) {
        // Only replace valid floor (50)
        const current = this.grid.getCell(x, 5, z); // Assuming flat floor at 5
        if (current === 50 && this.rng.chance(density)) {
          this.grid.setCell(x, 5, z, id);
          // Spread slightly
          if (this.rng.chance(0.5)) this.grid.setCell(x + 1, 5, z, id);
          if (this.rng.chance(0.5)) this.grid.setCell(x, 5, z + 1, id);
        }
      }
    }
  }

  dist2D(x1, z1, x2, z2) {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(z2 - z1, 2));
  }
}
