import type { Framebuffer } from "../engine/render/Framebuffer"
import type { RenderConfig } from "../engine/render/RenderConfig"
import { MOB_KINDS } from "../game/actors/Mob"
import { renderBand, MOB_FLOATS, type MobDraw, type Scene } from "../game/renderScene"

/** One-time setup: shared framebuffer + control/param buffers, the (cloned)
 *  scene, this worker's row band, and its index into the per-worker times array. */
type Init = {
  colorSAB: SharedArrayBuffer
  depthSAB: SharedArrayBuffer
  width: number
  height: number
  scene: Scene
  band: [number, number]
  config: RenderConfig
  skyStep: number
  ctrlSAB: SharedArrayBuffer
  camSAB: SharedArrayBuffer
  vpSAB: SharedArrayBuffer
  visSAB: SharedArrayBuffer
  mobSAB: SharedArrayBuffer
  timesSAB: SharedArrayBuffer
  index: number
}

const FRAME = 0
const DONE = 1
const VIS = 2
const MOBVIS = 3

const ctx = globalThis as unknown as {
  addEventListener: (type: "message", handler: (e: { data: Init }) => void) => void
}

ctx.addEventListener("message", (e) => {
  const m = e.data
  const fb: Framebuffer = {
    width: m.width,
    height: m.height,
    color: new Uint32Array(m.colorSAB),
    depth: new Float32Array(m.depthSAB),
  }
  const ctrl = new Int32Array(m.ctrlSAB)
  const cam = new Float64Array(m.camSAB)
  const vp = new Float32Array(m.vpSAB)
  const vis = new Int32Array(m.visSAB)
  const mob = new Float32Array(m.mobSAB)
  const times = new Float64Array(m.timesSAB)
  const { scene, band, config, skyStep, index } = m

  // Lock-free frame loop: block until main bumps the frame counter, render this
  // band, record the band time, and signal done. No messages per frame.
  let last = 0
  for (;;) {
    Atomics.wait(ctrl, FRAME, last)
    last = Atomics.load(ctrl, FRAME)
    const t0 = performance.now()
    const camera = { position: { x: cam[0], y: cam[1], z: cam[2] }, yaw: cam[3], pitch: cam[4], fov: cam[5] }
    const count = Atomics.load(ctrl, VIS)
    const visible = [...vis.subarray(0, count)]
    const mobCount = Atomics.load(ctrl, MOBVIS)
    const mobDraws: MobDraw[] = []
    for (let i = 0; i < mobCount; i++) {
      const o = i * MOB_FLOATS
      mobDraws.push({ kind: MOB_KINDS[mob[o]] ?? "frog", x: mob[o + 1], y: mob[o + 2], z: mob[o + 3], heading: mob[o + 4], scale: mob[o + 5] })
    }
    renderBand(fb, scene, camera, vp, visible, mobDraws, config, skyStep, cam[6], band[0], band[1])
    times[index] = performance.now() - t0
    Atomics.add(ctrl, DONE, 1)
  }
})
