import { NULL_POINTER } from "../BinaryTopology.js";

const scratch_coord = [0, 0, 0];


/**
 * A degenerate face is one that has zero area.
 *
 * @param {BinaryTopology} mesh
 * @param {number} face
 * @returns {boolean}
 */
export function bt_face_is_degenerate(mesh, face) {
    const first_loop = mesh.face_read_loop(face);

    // A face with no loops is topologically degenerate
    if (first_loop === NULL_POINTER) {
        return true;
    }

    let current_loop = first_loop;
    let loop_count = 0;

    // Components for the Newell's method normal vector
    let nx = 0.0;
    let ny = 0.0;
    let nz = 0.0;

    // Read the starting vertex
    const first_vertex = mesh.loop_read_vertex(current_loop);
    mesh.vertex_read_coordinate(scratch_coord, 0, first_vertex);

    // to avoid magnitude issue issues in Newell's method, we shift all vertices to a common local reference

    const reference_x = scratch_coord[0];
    const reference_y = scratch_coord[1];
    const reference_z = scratch_coord[2];

    let current_x = 0;
    let current_y = 0;
    let current_z = 0;

    do {
        const next_loop = mesh.loop_read_next(current_loop);
        const next_vertex = mesh.loop_read_vertex(next_loop);

        // Read the next vertex in the cycle
        mesh.vertex_read_coordinate(scratch_coord, 0, next_vertex);

        const next_x = scratch_coord[0] - reference_x;
        const next_y = scratch_coord[1] - reference_y;
        const next_z = scratch_coord[2] - reference_z;

        // Newell's method cross-product accumulations
        nx += (current_y - next_y) * (current_z + next_z);
        ny += (current_z - next_z) * (current_x + next_x);
        nz += (current_x - next_x) * (current_y + next_y);

        // Shift next to current for the next iteration
        current_x = next_x;
        current_y = next_y;
        current_z = next_z;

        current_loop = next_loop;
        loop_count++;
    } while (current_loop !== first_loop);

    // A face with fewer than 3 vertices cannot have an area
    if (loop_count < 3) {
        return true;
    }

    // The length of the Newell vector is twice the area of the polygon.
    // We can just check the squared length against a small epsilon.
    const area_squared = (nx * nx) + (ny * ny) + (nz * nz);

    return area_squared <= 1e-17;
}