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

/**
 * Given a face, get a list of its neighbors.
 * Two faces are neighbours if they share an edge.
 * @param {number[]|Uint32Array} output
 * @param {number} output_offset
 * @param {BinaryTopology} mesh
 * @param {number} face_id
 * @returns {number} number of faces written to output
 * @see bt_face_get_attached_faces
 */
export function bt_face_get_neighbour_faces(
    output,
    output_offset,
    mesh,
    face_id
) {
    assert.isArrayLike(output, "output");
    assert.isNonNegativeInteger(output_offset, "output_offset");
    assert.isNonNegativeInteger(face_id, "face_id");
    assert.defined(mesh, "mesh");
    assert.notNull(mesh, "mesh");
    assert.isObject(mesh, "mesh");
    assert.equal(mesh.isBinaryTopology, true, "mesh.isBinaryTopology !== true");

    let count = 0;
    const start_loop = mesh.face_read_loop(face_id);

    // If the face has no loops (e.g., NULL_POINTER: 0xFFFFFFFF), it has no neighbors
    if (start_loop === NULL_POINTER) {
        return 0;
    }

    let current_loop = start_loop;

    do {
        // Traverse the radial cycle around the edge to find adjacent faces
        let radial_loop = mesh.loop_read_radial_next(current_loop);

        while (radial_loop !== current_loop) {
            const neighbor_face = mesh.loop_read_face(radial_loop);

            // Ensure we aren't adding the original face itself
            if (neighbor_face !== face_id) {

                // Check if we've already added this face (prevents duplicates
                // if two faces share more than one edge)
                let is_duplicate = false;

                for (let i = 0; i < count; i++) {
                    if (output[output_offset + i] === neighbor_face) {
                        is_duplicate = true;
                        break;
                    }
                }

                if (!is_duplicate) {
                    output[output_offset + count] = neighbor_face;
                    count++;
                }
            }

            radial_loop = mesh.loop_read_radial_next(radial_loop);
        }

        // Move to the next boundary loop of the original face
        current_loop = mesh.loop_read_next(current_loop);

    } while (current_loop !== start_loop);

    return count;
}