// The scene camera — a Node (so position / lookAt / transform all work) plus projection reads and
// screen↔world ray helpers. Created and attached by Scene. Ported from worker/src/components/Camera.ts.

import { Vec3 } from "../math/vec"
import { Node } from "./Node"
import { Ray } from "./Ray"

export class Camera extends Node {
  private _sceneId = -1
  /** Live projection matrix (updated by the host when the viewport/fov changes). */
  readonly projectionMatrix = new Float32Array(16)

  /** @internal — Scene wires the camera to its native scene id + projection callback. */
  _attach(sceneId: number): void {
    this._sceneId = sceneId
    _creator.attachCameraToAR(sceneId, this.id, (mat) => {
      for (let i = 0; i < 16; i++) this.projectionMatrix[i] = mat[i]
    })
  }

  get fov(): number { return _creator.getCameraFov(this._sceneId, 0) }
  get horizontalFov(): number { return _creator.getCameraFov(this._sceneId, 1) }
  get displaySize(): [number, number] {
    const s = _creator.getDisplaySize()
    return [ s[0], s[1] ]
  }

  /** World-space ray direction through a screen pixel. */
  getViewDirection(screenX: number, screenY: number): Vec3 {
    if (this._sceneId < 0) throw new Error("Camera is not attached to a scene")
    const v = new Float32Array(3)
    _creator.getCameraViewDirection(this._sceneId, screenX, screenY, v)
    return new Vec3(v[0], v[1], v[2])
  }

  /** A pick ray from the camera through a screen pixel. */
  getRay(screenX: number, screenY: number): Ray {
    return new Ray(this.worldPosition, this.getViewDirection(screenX, screenY))
  }
}
