// A trigger zone, as an aspect on a 3D Node. Requires a Shape (its geometry); creates a static SENSOR
// body from it, so a physics body overlapping the zone fires the node's 'enter' / 'exit' events
// instead of colliding. A trigger does not block movement, and is still pointer-pickable.
//
//   const goal = new Mesh(box(), material)
//     .aspect(Shape, { box: [1, 2, 1] })
//     .aspect(Trigger)
//   goal.addEventListener('enter', other => win(other))
//   goal.addEventListener('exit',  other => …)

import { Aspect } from "../core/Aspect"
import { cx, cy, cz, type Vec3Like } from "../math/vec"
import { Shape } from "./Shape"
import { ensurePhysicsEvents } from "./physicsEvents"
import type { Node } from "./Node"

export class Trigger extends Aspect<"trigger", Node> {
  static readonly aspect = "trigger"

  private _bodyId = 0
  /** Native body id (0 if no physics support). */
  get id(): number { return this._bodyId }

  onAttach(): void {
    if (!_creator.physicsHasSupport || !_creator.physicsHasSupport()) return
    const shape = this.node.get(Shape)
    if (!shape) {
      throw new Error("Trigger requires a Shape aspect — add it first: node.aspect(Shape, {…}).aspect(Trigger)")
    }
    const shapeId = shape._claim()
    this._bodyId = _creator.physicsCreateBody(this.node.id, shapeId, 0 /* static */, 0, true /* sensor */, false)
    shape._ownBody(this._bodyId)
    ensurePhysicsEvents() // routes overlap events → the node's 'enter' / 'exit'
  }

  onDetach(): void {
    if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
    this.node.get(Shape)?._recreatePickBody()
  }

  /** Reposition the trigger zone to a world point. */
  moveTo(p: Vec3Like): this {
    if (this._bodyId) _creator.physicsSetBodyPosition(this._bodyId, cx(p), cy(p), cz(p))
    return this
  }
}
