import { assert } from "../../assert.js";
import Vector3 from "../Vector3.js";

/**
 * Used for representing points on a 3D surface. Used for Ray Casting contacts
 */
export class SurfacePoint3 {

    /**
     * @readonly
     * @type {Vector3}
     */
    normal = new Vector3(0, 1, 0);

    /**
     * @readonly
     * @type {Vector3}
     */
    position = new Vector3(0, 0, 0);

    /**
     * Primitive index, such as triangle/point/line from the source geometry
     * optional
     * @type {number}
     */
    index = -1;

    get 0() {
        return this.position.x;
    }

    get 1() {
        return this.position.y;
    }

    get 2() {
        return this.position.z;
    }

    get 3() {
        return this.normal.x;
    }

    get 4() {
        return this.normal.y;
    }

    get 5() {
        return this.normal.z;
    }

    /**
     *
     * @param {number[]|mat4|Float32Array} m
     */
    applyMatrix4(m) {
        assert.defined(m, 'matrix');
        assert.notNull(m, 'matrix');

        this.position.applyMatrix4(m);
        this.normal.applyDirectionMatrix4(m);
    }

    /**
     *
     * @param {number[]|ArrayLike<number>|Float32Array} array
     * @param {number} [offset=0]
     */
    fromArray(array, offset = 0) {
        this.position.fromArray(array, offset);
        this.normal.fromArray(array, offset + 3);
    }

    /**
     *
     * @param {number[]|ArrayLike<number>|Float32Array} array
     * @param {number} [offset=0]
     */
    toArray(array, offset = 0) {
        this.position.toArray(array, offset);
        this.normal.toArray(array, offset + 3);
    }

    /**
     *
     * @param {SurfacePoint3} other
     * @returns {boolean}
     */
    equals(other) {
        return this.index === other.index
            && this.position.equals(other.position)
            && this.normal.equals(other.normal);
    }

    /**
     *
     * @param {SurfacePoint3} other
     */
    copy(other) {
        this.position.copy(other.position);
        this.normal.copy(other.normal);
        this.index = other.index;
    }

    /**
     *
     * @returns {SurfacePoint3}
     */
    clone() {
        const r = new SurfacePoint3();

        r.copy(this);

        return r;
    }
}
