import { BaseGenerator } from "./BaseGenerator.js";
import { TrenchTextureGenerator } from "./textures/TrenchTextureGenerator.js";
import { SimplexNoise } from "../utils/SimplexNoise.js";

/**
 * Generates "Contested Frontier" biome:
 * - Linear trench lanes.
 * - Shell craters.
 * - Fortifications.
 */
export class ContestedFrontierGenerator extends BaseGenerator {
  constructor(grid, seed) {
    super(grid, seed);

    this.textureGen = new TrenchTextureGenerator(seed);
    this.generatedAssets = {
      palette: {},
      spawnZones: { player: [], enemy: [] },
    };

    this.preloadTextures();
  }

  preloadTextures() {
    const VARIATIONS = 10;
    const TEXTURE_SIZE = 128;

    // Walls (120-129)
    for (let i = 0; i < VARIATIONS; i++) {
      const seed = this.seed + i * 100;
      this.generatedAssets.palette[120 + i] = this.textureGen.generateWall(
        TEXTURE_SIZE,
        seed
      );
    }

    // Floors (220-229)
    // We split into 3 tiers of 3-4 variants each
    // 220-222: Muddy (Bias -0.6)
    // 223-226: Mixed (Bias 0.0)
    // 227-229: Grassy (Bias 0.6)

    // Muddy
    for (let i = 0; i < 3; i++) {
      const seed = this.seed + i * 200;
      this.generatedAssets.palette[220 + i] = this.textureGen.generateFloor(
        TEXTURE_SIZE,
        seed,
        -0.6
      );
    }
    // Mixed
    for (let i = 0; i < 4; i++) {
      const seed = this.seed + (i + 3) * 200;
      this.generatedAssets.palette[223 + i] = this.textureGen.generateFloor(
        TEXTURE_SIZE,
        seed,
        0.0
      );
    }
    // Grassy
    for (let i = 0; i < 3; i++) {
      const seed = this.seed + (i + 7) * 200;
      this.generatedAssets.palette[227 + i] = this.textureGen.generateFloor(
        TEXTURE_SIZE,
        seed,
        0.6
      );
    }
  }

  generate() {
    // 1. Terrain Shape
    // We want a central trench (lower Y) surrounded by higher ground (banks).
    // The trench should meander slightly along the Z-axis (if lane is X-axis) or X-axis (if lane is Z-axis).
    // Let's assume the "Lane" is along the Z-axis (player starts at Z=0, enemy at Z=end).

    const trenchNoise = new SimplexNoise(this.seed);

    // Parameters
    const bankHeight = 5;
    const trenchFloorY = 2; // Depth of trench
    const trenchWidth = 8; // Width in blocks

    for (let x = 0; x < this.width; x++) {
      for (let z = 0; z < this.depth; z++) {
        // Calculate Trench Center per Z slice
        // Meander the center X coordinate
        const meander = trenchNoise.noise2D(z * 0.1, 0) * (this.width * 0.2);
        const centerX = this.width / 2 + meander;

        // Distance from current X to center X
        const dist = Math.abs(x - centerX);

        // Determine Ground Height
        // If within trench width, low height. If outside, bank height.
        // We use smooth interpolation for a slope
        let targetHeight = bankHeight;

        const halfWidth = trenchWidth / 2;
        if (dist < halfWidth) {
          targetHeight = trenchFloorY;
        } else if (dist < halfWidth + 3) {
          // Slope area (3 blocks wide)
          const t = (dist - halfWidth) / 3; // 0 to 1
          targetHeight = trenchFloorY + t * (bankHeight - trenchFloorY);
        }

        // Add some noise to the ground height
        const groundNoise = trenchNoise.noise2D(x * 0.2, z * 0.2) * 1.5;
        let yHeight = Math.floor(targetHeight + groundNoise);

        // Clamp height
        if (yHeight < 1) yHeight = 1;
        if (yHeight > this.height - 2) yHeight = this.height - 2;

        // Fill Voxels
        for (let y = 0; y <= yHeight; y++) {
          // Pick Texture ID
          // If it's a "Wall" (vertical step) use 120+, else Floor 220+
          // Simple heuristic: fill solid. We will texture pass later.
          this.grid.setCell(x, y, z, 1); // Temp solid
        }
      }
    }

    // 2. Texture Pass
    this.applyTextures();

    // 3. Scatter Fortifications (Sandbags, etc)
    this.scatterFortifications();

    // 4. Scatter Nature (Stumps, Rocks)
    this.scatterCover(10, 0.03); // Use standard cover ID 10 for nature

    // 5. Define Spawn Zones
    // Player at Z-Start, Enemy at Z-End
    for (let x = 1; x < this.width - 1; x++) {
      for (let z = 1; z < 5; z++) {
        // Player Zone (Z < 5)
        this.checkSpawnSpot(x, z, "player");
      }
      for (let z = this.depth - 6; z < this.depth - 1; z++) {
        // Enemy Zone (Z > Depth-6)
        this.checkSpawnSpot(x, z, "enemy");
      }
    }
  }

  checkSpawnSpot(x, z, type) {
    // Find surface Y
    let y = this.height - 1;
    while (y > 0 && this.grid.getCell(x, y, z) === 0) {
      y--;
    }

    // Must be solid floor
    if (this.grid.getCell(x, y, z) !== 0) {
      // Add spawn (standing one block above floor)
      this.generatedAssets.spawnZones[type].push({ x, y: y + 1, z });
    }
  }

  applyTextures() {
    // Noise for biome distribution (Mud vs Grass patches)
    // Frequency 0.1 gives similar scale to existing generators
    const biomeNoise = new SimplexNoise(this.seed + 999);

    for (let x = 0; x < this.width; x++) {
      for (let z = 0; z < this.depth; z++) {
        // Find surface Y
        let maxY = -1;
        for (let y = this.height - 1; y >= 0; y--) {
          if (this.grid.getCell(x, y, z) !== 0) {
            maxY = y;
            break;
          }
        }

        if (maxY !== -1) {
          // Determine Biome Patch Type
          const noiseVal = biomeNoise.noise2D(x * 0.15, z * 0.15); // -1 to 1

          let textureId;

          if (noiseVal < -0.3) {
            // Muddy Patch (220-222)
            textureId = 220 + this.rng.rangeInt(0, 2);
          } else if (noiseVal > 0.3) {
            // Grassy Patch (227-229)
            textureId = 227 + this.rng.rangeInt(0, 2);
          } else {
            // Mixed Patch (223-226)
            textureId = 223 + this.rng.rangeInt(0, 3);
          }

          // Surface Block: Floor Texture
          this.grid.setCell(x, maxY, z, textureId);

          // Blocks below: Wall/Dirt Texture
          for (let y = 0; y < maxY; y++) {
            this.grid.setCell(x, y, z, 120 + (y % 5)); // varied dirt
          }
        }
      }
    }
  }

  scatterFortifications() {
    // Place Sandbags (ID 12) along the edges of the trench (Top of the slope)
    // Logic: If I am on a high block and neighbor is significantly lower, place sandbag

    for (let x = 1; x < this.width - 1; x++) {
      for (let z = 1; z < this.depth - 1; z++) {
        // Find surface y
        let y = 0;
        while (y < this.height && this.grid.getCell(x, y + 1, z) !== 0) {
          y++;
        }
        // y is now the top solid block level (assuming we found one)
        if (this.grid.getCell(x, y, z) === 0) continue; // Should be solid

        // Check neighbors for dropoff
        const neighbors = [
          { x: x + 1, z },
          { x: x - 1, z },
          { x, z: z + 1 },
          { x, z: z - 1 },
        ];

        let isRidge = false;
        for (const n of neighbors) {
          // Get neighbor height
          let ny = 0;
          // scan up to reasonable height
          while (
            ny < this.height &&
            this.grid.getCell(n.x, ny + 1, n.z) !== 0
          ) {
            ny++;
          }

          // If neighbor is 2+ blocks lower, we are on a ridge/trench lip
          if (y > ny + 1) {
            isRidge = true;
            break;
          }
        }

        if (isRidge && this.rng.chance(0.4)) {
          // Place Sandbag on top (y+1)
          this.grid.setCell(x, y + 1, z, 12);
        }
      }
    }
  }
}
