import { solve_linear_system } from "../../../math/linalg/solve_linear_system.js";
import { v3_dot } from "../../vec3/v3_dot.js";

const MAX_FLOAT32 = 3.4028234663852886e+38;

const n12 = new Float64Array(3);
const n13 = new Float64Array(3);
const n14 = new Float64Array(3);

const x12 = new Float64Array(3);
const x13 = new Float64Array(3);
const x14 = new Float64Array(3);

const A = new Float64Array(9);

const rhs = new Float64Array(3);

/**
 * Compute the circumcenter (center[3]) and radius squared (method return value) of a tetrahedron defined by the four points x1, x2, x3, and x4.
 *
 * @see https://github.com/Kitware/VTK/blob/ac3fd8005bce7b3da4423c305f61ffd9df9695ef/Common/DataModel/vtkTetra.cxx
 * @param {number[]} result [center_x, center_y, center_z, radius_squared]
 * @param {number[]} points
 * @param {number} a
 * @param {number} b
 * @param {number} c
 * @param {number} d
 */
export function tetrahedron_compute_circumsphere(
    result,
    points,
    a, b, c, d
) {

    // calculate normals and intersection points of bisecting planes.
    for (let i = 0; i < 3; i++) {
        const v_a = points[a * 3 + i];
        const v_b = points[b * 3 + i];
        const v_c = points[c * 3 + i];
        const v_d = points[d * 3 + i];

        n12[i] = v_b - v_a;
        n13[i] = v_c - v_a;
        n14[i] = v_d - v_a;

        x12[i] = (v_b + v_a) * 0.5;
        x13[i] = (v_c + v_a) * 0.5;
        x14[i] = (v_d + v_a) * 0.5;
    }

    // Pack A column-major (solve_linear_system expects column-major). The
    // math matrix rows are n12, n13, n14, so column j of A holds the j-th
    // component of each normal: [n12[j], n13[j], n14[j]].
    A[0] = n12[0]; A[1] = n13[0]; A[2] = n14[0];
    A[3] = n12[1]; A[4] = n13[1]; A[5] = n14[1];
    A[6] = n12[2]; A[7] = n13[2]; A[8] = n14[2];

    rhs[0] = v3_dot(n12[0], n12[1], n12[2], x12[0], x12[1], x12[2]);
    rhs[1] = v3_dot(n13[0], n13[1], n13[2], x13[0], x13[1], x13[2]);
    rhs[2] = v3_dot(n14[0], n14[1], n14[2], x14[0], x14[1], x14[2]);

    // Solve system of equations
    if (solve_linear_system(A, rhs, 3) === false) {

        // failed to solve, fall-back to infinitely-sized sphere centered around origin
        result[0] = result[1] = result[2] = 0;
        result[3] = MAX_FLOAT32;
        return;

    } else {

        result[0] = rhs[0];
        result[1] = rhs[1];
        result[2] = rhs[2];

    }

    let sum = 0;
    let diff;

    for (let i = 0; i < 3; i++) {
        const rhs_offset = rhs[i];

        diff = points[a * 3 + i] - rhs_offset;
        sum += diff * diff;

        diff = points[b * 3 + i] - rhs_offset;
        sum += diff * diff;

        diff = points[c * 3 + i] - rhs_offset;
        sum += diff * diff;

        diff = points[d * 3 + i] - rhs_offset;
        sum += diff * diff;
    }

    // divide
    sum *= 0.25;

    if (sum >= MAX_FLOAT32) {
        result[3] = MAX_FLOAT32;
    } else {
        result[3] = sum;
    }
}


