// Pot throwing physics: arc a pot 2-3 tiles, shatter on landing, scatter shards.

import { TILE, COLS, ROWS, THROW_TILES, SHARDS_PER_POT, Z } from "./config.js";
import { visual } from "./sprites.js";

const DIRS8 = [
  [1, 0], [-1, 0], [0, 1], [0, -1],
  [1, 1], [1, -1], [-1, 1], [-1, -1],
];

const randint = (k, [min, max]) => min + Math.floor(k.rand() * (max - min + 1));
const inBounds = (x, y) => x >= 0 && y >= 0 && x < COLS && y < ROWS;

// Throw from `fromPos`, run the arc, shatter, spawn shards. Calls onDone() when
// the pot has landed and shattered.
export function throwPot(k, world, fromPos, onDone) {
  const from = world.toTile(fromPos);
  const [dx, dy] = k.choose(DIRS8);
  const dist = randint(k, THROW_TILES);

  // Walk outward to the requested distance, stopping at the last passable tile.
  let land = { ...from };
  for (let step = 1; step <= dist; step++) {
    const nx = from.x + dx * step;
    const ny = from.y + dy * step;
    if (!inBounds(nx, ny) || !world.walkable(nx, ny)) break;
    land = { x: nx, y: ny };
  }

  const start = fromPos.clone();
  const end = world.tc(land);
  const dur = 0.45;
  const peak = 46; // arc height in px

  // Shadow on the ground + the flying pot above it.
  const shadow = k.add([
    k.circle(9),
    k.pos(end),
    k.anchor("center"),
    k.scale(1, 0.5), // flatten into an oval
    k.color(0, 0, 0),
    k.opacity(0.25),
    k.z(Z.GROUND + 1),
  ]);
  const flying = k.add([...visual(k, "pot"), k.pos(start), k.z(Z.FLYING)]);

  k.tween(0, 1, dur, (t) => {
    const x = k.lerp(start.x, end.x, t);
    const y = k.lerp(start.y, end.y, t);
    const arc = peak * 4 * t * (1 - t); // parabola, 0 at ends
    flying.pos = k.vec2(x, y - arc);
    shadow.opacity = 0.15 + 0.15 * (1 - Math.abs(0.5 - t) * 2);
  }, k.easings.linear).then(() => {
    flying.destroy();
    shadow.destroy();
    shatter(k, world, land, end);
    onDone && onDone();
  });
}

function shatter(k, world, landTile, landPos) {
  k.shake(4);
  burst(k, landPos);

  const count = randint(k, SHARDS_PER_POT);
  // Candidate tiles: landing tile first, then a shuffled set of neighbors.
  const neighbors = [
    [0, 0], [1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1],
  ];
  const candidates = [];
  for (const [ox, oy] of neighbors) {
    const x = landTile.x + ox;
    const y = landTile.y + oy;
    if (inBounds(x, y) && world.walkable(x, y)) candidates.push({ x, y });
  }
  // Keep landing tile at the front; shuffle the rest (seeded).
  for (let i = candidates.length - 1; i > 1; i--) {
    const j = 1 + Math.floor(k.rand() * i);
    [candidates[i], candidates[j]] = [candidates[j], candidates[i]];
  }

  let placed = 0;
  for (const t of candidates) {
    if (placed >= count) break;
    spawnShard(k, world, t);
    placed++;
  }
  world.onShardsChanged();
}

// A quick asset-free shatter flash.
function burst(k, pos) {
  const ring = k.add([
    k.circle(6),
    k.pos(pos),
    k.anchor("center"),
    k.color(255, 240, 210),
    k.opacity(0.9),
    k.z(Z.FLYING),
  ]);
  k.tween(6, 22, 0.25, (r) => (ring.radius = r), k.easings.easeOutQuad);
  k.tween(0.9, 0, 0.25, (o) => (ring.opacity = o), k.easings.linear).then(() =>
    ring.destroy()
  );
}

function spawnShard(k, world, tile) {
  const p = world.tc(tile);
  // Small random jitter so multiple shards don't perfectly overlap tile centers.
  const jx = (k.rand() - 0.5) * TILE * 0.4;
  const jy = (k.rand() - 0.5) * TILE * 0.4;
  const s = k.add([
    ...visual(k, "shard"),
    k.pos(p.x + jx, p.y + jy),
    k.area({ scale: 0.55 }),
    k.z(p.y),
    k.rotate((k.rand() - 0.5) * 24), // slight tilt; keep debris upright-ish
    "shard",
  ]);
  return s;
}
