import { lerp } from "../../../math/lerp.js";
import Vector3 from "../../Vector3.js";
import { v3_dot } from "../../vec3/v3_dot.js";
import { v3_length_sqr } from "../../vec3/v3_length_sqr.js";
import { v3_slerp } from "../../vec3/v3_slerp.js";
import { EPSILON } from "../../../math/EPSILON.js";

const e = new Vector3();

const point = new Vector3();

const v0 = new Vector3();
const v1 = new Vector3();

/**
 * @see https://stackoverflow.com/a/57824137
 * @param {number[]} destination
 * @param {number} destination_offset
 * @param {number} a_normal_x
 * @param {number} a_normal_y
 * @param {number} a_normal_z
 * @param {number} a_constant
 * @param {number} b_normal_x
 * @param {number} b_normal_y
 * @param {number} b_normal_z
 * @param {number} b_constant
 * @param {number} t
 */
export function plane3_slerp(
    destination, destination_offset,
    a_normal_x, a_normal_y, a_normal_z, a_constant,
    b_normal_x, b_normal_y, b_normal_z, b_constant,
    t
) {

    // The common line of the two planes is along the (non-unit) direction
    e._crossVectors(
        a_normal_x, a_normal_y, a_normal_z,
        b_normal_x, b_normal_y, b_normal_z
    );

    const determinant = v3_length_sqr(e.x, e.y, e.z);

    if (determinant < EPSILON) {
        // no intersection, planes are parallel

        // determine if planes are facing the same direction or not
        const d = v3_dot(
            a_normal_x, a_normal_y, a_normal_z,
            b_normal_x, b_normal_y, b_normal_z
        );

        // if planes are parallel, we assume normal of one of the planes
        destination[destination_offset] = a_normal_x;
        destination[destination_offset + 1] = a_normal_y;
        destination[destination_offset + 2] = a_normal_z;

        destination[destination_offset + 3] = lerp(a_constant, b_constant * d, t);

        return;
    }

    v0._crossVectors(
        a_normal_x, a_normal_y, a_normal_z,
        e.x, e.y, e.z
    );
    v0.multiplyScalar(b_constant);

    v1._crossVectors(
        b_normal_x, b_normal_y, b_normal_z,
        e.x, e.y, e.z
    );
    v1.multiplyScalar(a_constant);

    // The point on this line closest to the origin
    // point = (d_1*cross(n_2,e)-d_2*cross(n_1,e))/dot(e.e)
    point.subVectors(v0, v1);


    const inv_determinant = 1 / determinant;

    point.multiplyScalar(inv_determinant);

    // compute normal
    v3_slerp(
        v0,
        a_normal_x, a_normal_y, a_normal_z,
        b_normal_x, b_normal_y, b_normal_z,
        t
    );

    // compute distance (constant)
    const d = v3_dot(
        v0.x, v0.y, v0.z,
        point.x, point.y, point.z
    );

    destination[destination_offset] = v0.x;
    destination[destination_offset + 1] = v0.y;
    destination[destination_offset + 2] = v0.z;
    destination[destination_offset + 3] = -d;
}
