// Component writes on SDK-owned vectors — the runtime half of chisel's `comp_write` pass.
//
//   hero.controller.velocity.y = 7     →  __compWrite(hero.controller, "velocity", "y", 7)
//   hero.controller.velocity.y += 3    →  __compOp(hero.controller, "velocity", "y", 0, 3)
//
// A getter like `velocity` hands out a fresh Vec3, so the literal spelling would write to a copy and
// silently do nothing. chisel rewrites the exact `<owner>.<prop>.<x|y|z|w> = v` shape into these
// helpers, which ask the OWNER to apply the component write (no getter call, no allocation) and
// fall back to the plain write on anything else, so a user record `{ velocity: { x, y } }` behaves
// exactly as written. Only the direct spelling is covered: `const v = c.velocity; v.y = 7` is still
// a write to a copy.
//
// Owners today: Node / Node2D / Camera2D (`position` → the scalar setters, physics routing included),
// Physics (`velocity`, `angularVelocity`), CharacterController / CharacterController2D (`velocity`).
//
// An owner declares WHICH getters qualify as compile-time data and answers them at runtime:
//
//   static _comps = ["velocity"]                 // chisel reads the list, then strips it (0 bytes shipped)
//   _writeComp(prop, axis, value) { … }          // called for listed props only; a hook without the
//                                                // list is a build diagnostic and routes nothing

export type CompAxis = "x" | "y" | "z" | "w"

/** Implemented by a class whose vector getters accept component writes (see above). The class also
 *  carries `static _comps: string[]` naming those getters — compile-time data, absent at runtime. */
export interface CompWriter {
  _writeComp(prop: string, axis: CompAxis, value: number): void
}

/** `<o>.<prop>.<axis> = value`, routed to the owner when it has the hook. Returns the value. */
export const __compWrite = (o: any, prop: string, axis: CompAxis, value: number): number => {
  if (o._writeComp !== undefined) o._writeComp(prop, axis, value)   // a direct call, not .call — cheaper on QuickJS
  else o[prop][axis] = value
  return value
}

/** `<o>.<prop>.<axis> op= v` — `op`: 0 `+=`, 1 `-=`, 2 `*=`, 3 `/=`. The current component is read
 *  through the normal getter (one fresh vector), the result written like `__compWrite`. */
export const __compOp = (o: any, prop: string, axis: CompAxis, op: number, v: number): number => {
  const cur = o[prop][axis] as number
  return __compWrite(o, prop, axis, op === 0 ? cur + v : op === 1 ? cur - v : op === 2 ? cur * v : cur / v)
}
