import { GRID } from '../config.js';
import { makeValueNoise, mulberry32 } from '../utils.js';

/**
 * Tile world state. Flat typed arrays for speed — one slot per tile.
 */
export class Grid {
  constructor(seed) {
    this.size = GRID;
    this.n = GRID * GRID;
    this.seed = seed;

    this.terrain   = new Uint8Array(this.n);  // 0 grass, 1 water
    this.zone      = new Uint8Array(this.n);  // 0 none, 1 res, 2 com, 3 ind
    this.struct    = new Uint8Array(this.n);  // STRUCT enum (0 = none)
    this.level     = new Uint8Array(this.n);  // zone building level 1..3
    this.variant   = new Uint8Array(this.n);  // visual variant 0..2
    this.age       = new Uint16Array(this.n); // months since built/upgraded
    this.badMonths = new Uint8Array(this.n);  // consecutive unpowered months
    this.burning   = new Uint8Array(this.n);  // months left burning
    this.rubble    = new Uint8Array(this.n);
    this.powered   = new Uint8Array(this.n);
    this.anchor    = new Int32Array(this.n);  // multi-tile anchor index (self if none)
    this.scenery   = new Uint8Array(this.n);  // 0 none, 1 tree, 2 tall tree, 3 rock
    this.landValue = new Float32Array(this.n);
  }

  idx(x, z) { return z * this.size + x; }
  inB(x, z) { return x >= 0 && z >= 0 && x < this.size && z < this.size; }

  /** True if the tile relays electricity (roads, structures and zoned land do). */
  conducts(i) {
    if (this.rubble[i]) return false;
    return this.struct[i] !== 0 || this.zone[i] !== 0;
  }

  isDeveloped(i) { return this.zone[i] !== 0 && this.level[i] > 0 && !this.rubble[i]; }

  /** Generate an island map with a winding river, lakes and scenery. */
  generateTerrain() {
    const S = this.size;
    const noise = makeValueNoise(this.seed, 256);
    const noise2 = makeValueNoise(this.seed ^ 0x9e3779b9, 256);
    const rng = mulberry32(this.seed ^ 0xabcd1234);
    const phase = rng() * Math.PI * 2;
    const half = S / 2;

    for (let z = 0; z < S; z++) {
      for (let x = 0; x < S; x++) {
        const i = z * S + x;
        // base rolling height
        let h = noise(x * 0.085, z * 0.085) * 0.75 + noise(x * 0.22, z * 0.22) * 0.25;
        // island falloff — edges become ocean
        const dx = (x - half) / half, dz = (z - half) / half;
        const d = Math.sqrt(dx * dx + dz * dz) / Math.SQRT2;
        h *= Math.max(0, 1.06 - d * d * 1.35);
        this.terrain[i] = h < 0.30 ? 1 : 0;
      }
    }

    // winding river across the island
    for (let x = 0; x < S; x++) {
      const t = x / S;
      const cz = half + Math.sin(phase + t * 4.2) * (half * 0.42) + (noise2(t * 5.5, 3.7) - 0.5) * 14;
      const w = 1.6 + noise2(t * 8.0, 9.1) * 2.2;
      for (let z = Math.floor(cz - w - 1); z <= Math.ceil(cz + w + 1); z++) {
        if (!this.inB(x, z)) continue;
        const dd = Math.abs(z - cz);
        if (dd <= w) this.terrain[this.idx(x, z)] = 1;
      }
    }

    // scenery on grass
    for (let i = 0; i < this.n; i++) {
      if (this.terrain[i] !== 0) continue;
      const r = rng();
      if (r < 0.26) this.scenery[i] = 1;
      else if (r < 0.33) this.scenery[i] = 2;
      else if (r < 0.36) this.scenery[i] = 3;
    }
  }
}
