// Small shared helpers.

export function clamp(v, a, b) { return v < a ? a : v > b ? b : v; }
export function lerp(a, b, t) { return a + (b - a) * t; }

/** Deterministic seeded RNG (mulberry32). */
export function mulberry32(seed) {
  let a = seed >>> 0;
  return function () {
    a |= 0; a = (a + 0x6D2B79F5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

export function hashStr(s) {
  let h = 2166136261 >>> 0;
  for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); }
  return h >>> 0;
}

export function fmtMoney(n) {
  const neg = n < 0;
  const v = Math.round(Math.abs(n));
  let s;
  if (v >= 1e9) s = (v / 1e9).toFixed(2) + 'B';
  else if (v >= 1e6) s = (v / 1e6).toFixed(2) + 'M';
  else s = v.toLocaleString('en-US');
  return (neg ? '-$' : '$') + s;
}

export function fmtNum(n) {
  if (n >= 1e6) return (n / 1e6).toFixed(2) + 'M';
  if (n >= 10000) return (n / 1000).toFixed(1) + 'k';
  return Math.round(n).toLocaleString('en-US');
}

export function choice(rng, arr) { return arr[Math.floor(rng() * arr.length)]; }
export function randInt(rng, lo, hi) { return lo + Math.floor(rng() * (hi - lo + 1)); }

/** Simple value-noise on an integer lattice with bilinear smoothing. */
export function makeValueNoise(seed, size) {
  const rng = mulberry32(seed);
  const g = new Float32Array((size + 1) * (size + 1));
  for (let i = 0; i < g.length; i++) g[i] = rng();
  const at = (x, y) => g[((y % size + size) % size) * (size + 1) + ((x % size + size) % size)];
  return function noise(x, y) {
    const x0 = Math.floor(x), y0 = Math.floor(y);
    const fx = x - x0, fy = y - y0;
    const sx = fx * fx * (3 - 2 * fx), sy = fy * fy * (3 - 2 * fy);
    const n00 = at(x0, y0), n10 = at(x0 + 1, y0), n01 = at(x0, y0 + 1), n11 = at(x0 + 1, y0 + 1);
    return lerp(lerp(n00, n10, sx), lerp(n01, n11, sx), sy);
  };
}

/** Bresenham line between two tile coords. */
export function lineTiles(x0, y0, x1, y1) {
  const pts = [];
  let dx = Math.abs(x1 - x0), dy = Math.abs(y1 - y0);
  const sx = x0 < x1 ? 1 : -1, sy = y0 < y1 ? 1 : -1;
  let err = dx - dy;
  while (true) {
    pts.push([x0, y0]);
    if (x0 === x1 && y0 === y1) break;
    const e2 = 2 * err;
    if (e2 > -dy) { err -= dy; x0 += sx; }
    if (e2 < dx) { err += dx; y0 += sy; }
  }
  return pts;
}
