/**
 * Prowler — the night. Descends directly from MierGridWorld's Inimigo (2019):
 * a creature that gives the dark a cost, and firelight a meaning.
 *
 * Rules (all of them, no hidden ones):
 *   - The world spawns prowlers after dusk, away from light; dawn destroys them.
 *   - A prowler hunts the nearest inhabitant or hopper within sight.
 *   - It will not enter light (campfires, lit lamps) — the hearth is safe.
 *   - Its bite hurts (never kills — life floors at 1; eat to recover).
 *   - Strike it (act 'strike') three times and it dissolves; hit it once and
 *     it hesitates.
 *
 * So the survival loop is: night falls → keep to fire and walls, or carry the
 * fight to it. Shelter you *built* is shelter that matters.
 */
'use strict';

const SPEED = 0.5;
const SIGHT = 26;
const BITE_RANGE = 1.7;
const BITE_DAMAGE = 9;
const BITE_COOLDOWN = 25; // ticks between bites (~2.5s)
const MAX_LIFE = 100;
const FLINCH_TICKS = 12; // hesitation after being struck

class Prowler {
  constructor(o) {
    this.id = o.id;
    this.kind = 'prowler';
    this.x = o.x; this.z = o.z; this.y = 0;
    this.heading = (o.seed % 628) / 100;
    this.scale = o.scale != null ? o.scale : 1;
    this.life = o.life != null ? o.life : MAX_LIFE;
    this.maxLife = MAX_LIFE;
    this._cool = 0;
    this._flinch = 0;
    this._rng = (o.seed >>> 0) || 1;
  }

  _rand() {
    this._rng = (Math.imul(this._rng, 1664525) + 1013904223) >>> 0;
    return this._rng / 4294967296;
  }

  _step(world, speed) {
    const nx = this.x + Math.cos(this.heading) * speed;
    const nz = this.z + Math.sin(this.heading) * speed;
    const m = world.materialAt(nx, nz);
    if (!m || m.liquid || !m.walkable || world.blockedByProp(nx, nz, 0.5) || world.lightAt(nx, nz)) {
      this.heading += (this._rand() < 0.5 ? 1 : -1) * Math.PI * 0.6; // blocked or lit — veer off
    } else {
      this.x = nx;
      this.z = nz;
    }
  }

  update(world) {
    // Dawn dissolves it.
    if (world.timeInfo().phase !== 'night') { world.removeEntity(this.id); return; }
    if (this._cool > 0) this._cool--;
    if (this._flinch > 0) { this._flinch--; this.y = world.heightAt(this.x, this.z); return; }

    // Hunt: nearest inhabitant outside the light, else nearest hopper.
    let prey = null, pd = SIGHT * SIGHT, isInh = false;
    for (const inh of world.inhabitants.values()) {
      if (world.lightAt(inh.pose.x, inh.pose.z)) continue; // the fire keeps them safe
      const dx = inh.pose.x - this.x, dz = inh.pose.z - this.z, d = dx * dx + dz * dz;
      if (d < pd) { pd = d; prey = { x: inh.pose.x, z: inh.pose.z, inh }; isInh = true; }
    }
    if (!prey) {
      const h = world.nearestEntity('hopper', this.x, this.z, SIGHT);
      if (h) {
        const d = (h.x - this.x) ** 2 + (h.z - this.z) ** 2;
        if (d < pd) { pd = d; prey = { x: h.x, z: h.z, ent: h }; }
      }
    }

    if (prey) {
      const d = Math.sqrt(pd);
      if (d <= BITE_RANGE) {
        if (isInh && this._cool === 0) {
          const life = prey.inh.life;
          if (life) life.value = Math.max(1, life.value - BITE_DAMAGE);
          prey.inh.events.push('a prowler bit you — get to light, strike back, or run');
          this._cool = BITE_COOLDOWN;
        } else if (prey.ent) {
          world.removeEntity(prey.ent.id); // the night eats a hopper
        }
      } else {
        this.heading = Math.atan2(prey.z - this.z, prey.x - this.x);
        this._step(world, SPEED);
      }
    } else {
      if (this._rand() < 0.06) this.heading += (this._rand() - 0.5) * 2;
      this._step(world, SPEED * 0.6);
    }
    this.y = world.heightAt(this.x, this.z);
  }

  /** Take a hit from `strike`. Returns true if it dissolved. */
  struck(world, damage) {
    this.life -= damage;
    this._flinch = FLINCH_TICKS;
    if (this.life <= 0) { world.removeEntity(this.id); return true; }
    return false;
  }

  serialize() {
    return {
      id: this.id,
      kind: this.kind,
      pose: { x: this.x, y: this.y, z: this.z, heading: this.heading, rot: this.heading },
      scale: this.scale,
      life: this.life,
      maxLife: this.maxLife,
    };
  }
}

module.exports = { Prowler };
