// combat/index.js (Lane B) — the createCombat factory. Composes enemies + weapons and
// feeds them Lane C's level events. All the wiring, none of the behaviour.
//
// Update order inside a frame is load-bearing:
//   boot: player.update(dt)  ->  combat.update(dt)
//   here: enemies.update(dt) ->  weapons.update(dt)
// Enemies move first so weapons hit-test against this frame's positions, not last frame's.

import { createEnemies } from './enemies.js';
import { createWeapons } from './weapons.js';

export function createCombat({ scene, world, bus, rng, flags = {}, assets = null, player }) {
  const enemies = createEnemies({ scene, world, bus, rng, assets });
  const weapons = createWeapons({ scene, world, bus, rng, player, targets: enemies });

  enemies.setBlastFx((pos, size, dur) => weapons.spawnBlast(pos, size, dur));
  enemies.setOnDeath((e) => weapons.spawnBlast(e.pos, e.radius * 1.6, 0.3));

  const score = { value: 0, kills: 0 };

  // Lane C's events arrive on the bus as the player crosses their `s`. We only care about
  // `spawn`; checkpoints/hazards/bosses belong to C and E this round. Unknown types are
  // ignored on purpose — C may add event kinds without breaking combat.
  const offEvent = bus.on('level:event', (ev) => {
    if (!ev || ev.type !== 'spawn') return;
    const n = ev.count ?? 1;
    for (let i = 0; i < n; i++) {
      // fan the group out over a short stretch of s so a count of 6 is an encounter,
      // not a wall of enemies at one arclength
      enemies.spawn(ev.enemy, { s: (ev.s ?? 0) + i * 3.5, theta: ev.theta ?? null, rho: ev.rho ?? null });
    }
  });

  const offDie = bus.on('enemy:die', (e) => {
    score.value += e.score ?? 0;
    score.kills++;
  });

  function update(dt) {
    enemies.update(dt, player);
    weapons.update(dt);
    // combat's slice of the HUD state (E reads player:state for the flight half)
    bus.emit('combat:state', {
      heat: weapons.heat, heatMax: weapons.heatMax, overheated: weapons.overheated,
      ammo: weapons.ammo, ammoMax: weapons.ammoMax,
      score: score.value, kills: score.kills, enemies: enemies.count,
    });
  }

  return {
    update,
    enemies, weapons, score,
    dispose() {
      offEvent(); offDie();
      enemies.dispose(); weapons.dispose();
    },
  };
}
