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

/**
 * Generates the "Crystal Spires" biome.
 * Focus: High verticality, floating islands, and void hazards.
 */
export class CrystalSpiresGenerator extends BaseGenerator {
  /**
   * @param {number} spireCount - Number of main vertical pillars.
   * @param {number} islandCount - Number of floating platforms.
   */
  generate(spireCount = 3, islandCount = 8) {
    this.grid.fill(0); // Start with Void (Sky)

    // 1. Generate Main Spires (Vertical Columns)
    const spires = [];
    for (let i = 0; i < spireCount; i++) {
      const x = this.rng.rangeInt(4, this.width - 5);
      const z = this.rng.rangeInt(4, this.depth - 5);
      const radius = this.rng.rangeInt(2, 4);

      this.buildSpire(x, z, radius);
      spires.push({ x, z, radius });
    }

    // 2. Generate Floating Islands
    const islands = [];
    for (let i = 0; i < islandCount; i++) {
      const w = this.rng.rangeInt(2, 4);
      const d = this.rng.rangeInt(2, 4);
      const x = this.rng.rangeInt(1, this.width - w - 1);
      const z = this.rng.rangeInt(1, this.depth - d - 1);
      const y = this.rng.rangeInt(2, this.height - 3); // Keep away from very bottom/top

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

      // Avoid intersecting main spires too heavily (simple check)
      this.buildPlatform(island);
      islands.push(island);
    }

    // 3. Connect Islands (Light Bridges)
    // Simple strategy: Connect every island to the nearest Spire or other Island
    for (const island of islands) {
      const islandCenter = this.getPlatformCenter(island);

      // Find nearest Spire
      let nearestSpireDist = Infinity;
      let targetSpire = null;

      for (const spire of spires) {
        // Approximate spire center at island height
        const dist = this.dist2D(
          islandCenter.x,
          islandCenter.z,
          spire.x,
          spire.z
        );
        if (dist < nearestSpireDist) {
          nearestSpireDist = dist;
          targetSpire = { x: spire.x, y: islandCenter.y, z: spire.z };
        }
      }

      // Build Bridge to Spire
      if (targetSpire) {
        this.buildBridge(islandCenter, targetSpire);
      }
    }
  }

  buildSpire(centerX, centerZ, radius) {
    // Wiggle the spire as it goes up
    let currentX = centerX;
    let currentZ = centerZ;

    for (let y = 0; y < this.height; y++) {
      // Slight drift per layer
      if (this.rng.chance(0.3)) currentX += this.rng.rangeInt(-1, 1);
      if (this.rng.chance(0.3)) currentZ += this.rng.rangeInt(-1, 1);

      // Draw Circle
      for (let x = currentX - radius; x <= currentX + radius; x++) {
        for (let z = currentZ - radius; z <= currentZ + radius; z++) {
          if (this.dist2D(x, z, currentX, currentZ) <= radius) {
            // Core is ID 1 (Stone/Marble), Edges might be ID 15 (Crystal)
            const id = this.rng.chance(0.2) ? 15 : 1;
            this.grid.setCell(x, y, z, id);
          }
        }
      }
    }
  }

  buildPlatform(rect) {
    for (let x = rect.x; x < rect.x + rect.w; x++) {
      for (let z = rect.z; z < rect.z + rect.d; z++) {
        // Build solid platform
        this.grid.setCell(x, rect.y, z, 1);
        // Ensure headroom
        this.grid.setCell(x, rect.y + 1, z, 0);
        this.grid.setCell(x, rect.y + 2, z, 0);
      }
    }
  }

  buildBridge(start, end) {
    const dist = this.dist2D(start.x, start.z, end.x, end.z);
    const steps = Math.ceil(dist);

    const stepX = (end.x - start.x) / steps;
    const stepZ = (end.z - start.z) / steps;

    let currX = start.x;
    let currZ = start.z;
    const y = start.y; // Flat bridge for now

    for (let i = 0; i <= steps; i++) {
      const tx = Math.round(currX);
      const tz = Math.round(currZ);

      // Bridge Voxel ID 20 (Light Bridge)
      if (this.grid.getCell(tx, y, tz) === 0) {
        this.grid.setCell(tx, y, tz, 20);
      }

      currX += stepX;
      currZ += stepZ;
    }
  }

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

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