import Vector3 from "../../../core/geom/Vector3.js";

/**
 * Result of a {@link PhysicsSystem} query that resolves to a single surface
 * contact — raycast hit, sphere overlap nearest-point, shape-cast first
 * blocker, etc.
 *
 * The class is an *output parameter*: callers pre-allocate one (or pull one
 * from a frame-pool) and pass it into the query. The query writes the fields
 * on hit and returns `true`; on miss it returns `false` and leaves the
 * fields untouched.
 *
 * Pre-allocation matters because a query that gets called every frame (a
 * ground sensor, a hover beam) would otherwise drop a small object on the
 * GC per call. Reusing the same `PhysicsSurfacePoint` keeps that allocation
 * out of the hot path.
 *
 * Field layout chosen to match what gameplay code typically needs:
 *   - `position` — world-space point on the surface
 *   - `normal` — surface normal at that point (broadphase queries return
 *     the AABB face normal as an approximation; narrowphase-refined queries
 *     would return the true shape normal at the same call site)
 *   - `t` — distance along the input ray, sphere-cast, etc. Useful when the
 *     caller wants to interpolate or step along the query primitive
 *     (`origin + t·direction` reconstructs the hit point exactly without
 *     reading `position`, which the deferred-execution physics events bus
 *     would otherwise need to copy).
 *   - `entity` — entity id that owns the hit body
 *   - `body_id` — packed body id (index << 8 | generation); stale after the
 *     body is unlinked, so prefer `entity` for any cross-frame retention.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class PhysicsSurfacePoint {

    constructor() {
        /**
         * World-space point on the hit surface.
         * @readonly
         * @type {Vector3}
         */
        this.position = new Vector3();

        /**
         * Surface normal at {@link position}, unit length. For broadphase-only
         * queries this is the AABB face normal (axis-aligned), which is exact
         * for AABB-shaped colliders and a stable approximation otherwise.
         * @readonly
         * @type {Vector3}
         */
        this.normal = new Vector3();

        /**
         * Parametric distance from the query origin to {@link position}, in
         * the same units as the input direction's magnitude (so for a unit-
         * length ray direction this is metres).
         * @type {number}
         */
        this.t = 0;

        /**
         * Entity that owns the hit body, or `-1` if no body owns it.
         * @type {number}
         */
        this.entity = -1;

        /**
         * Packed body id (index << 8 | generation). Goes stale once the body
         * is unlinked from the {@link PhysicsSystem}; prefer {@link entity}
         * for any cross-frame use.
         * @type {number}
         */
        this.body_id = -1;
    }

    /**
     * Reset to a "no hit" state. Optional — the query convention is that the
     * fields are only meaningful when the call returns `true`, so callers
     * that always branch on the return value don't need to reset. Useful for
     * debugger inspection and for tests that want to verify the query
     * doesn't accidentally touch the result on miss.
     */
    reset() {
        const p = this.position;
        const n = this.normal;
        p[0] = 0; p[1] = 0; p[2] = 0;
        n[0] = 0; n[1] = 0; n[2] = 0;
        this.t = 0;
        this.entity = -1;
        this.body_id = -1;
    }
}

/**
 * Fast type-check marker.
 * @readonly
 * @type {boolean}
 */
PhysicsSurfacePoint.prototype.isPhysicsSurfacePoint = true;
