import { INTERNAL_RND_SORT_SEED } from "./constants/INTERNAL_RND_SORT_SEED.js";
import { QuickSortEdges } from "./QuickSortEdges.js";
import { vec3 } from "gl-matrix";
import { GetEdge } from "./GetEdge.js";

/**
 *
 * @param {STriInfo[]} pTriInfos
 * @param {number[]|Float32Array} pEdges
 * @param {number[]} piTriListIn
 * @param {number} iNrTrianglesIn
 * @returns {void}
 */
export function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
    // build array of edges
    const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?

    for (let f = 0; f < iNrTrianglesIn; f++) {
        for (let i = 0; i < 3; i++) {

            const edge_index = f * 3 + i;

            const i0 = piTriListIn[edge_index];
            const i1 = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];

            pEdges[edge_index * 3] = i0 < i1 ? i0 : i1;			    // put minimum index in i0
            pEdges[edge_index * 3 + 1] = !(i0 < i1) ? i0 : i1;		// put maximum index in i1
            pEdges[edge_index * 3 + 2] = f;							// record face number
        }
    }

    // sort over all edges by i0, this is a pricey one.
    QuickSortEdges(pEdges, 0, iNrTrianglesIn * 3 - 1, 0, uSeed);	// sort channel 0 which is i0

    // sub sort over i1, should be fast.
    // could replace this with a 64 bit int sort over (i0,i1)
    // with i0 as msb in the quicksort call above.
    const iEntries = iNrTrianglesIn * 3;
    let iCurStartIndex = 0;

    for (let i = 1; i < iEntries; i++) {
        if (pEdges[iCurStartIndex * 3] !== pEdges[i * 3]) {

            const iL = iCurStartIndex;
            const iR = i - 1;
            //const int iElems = i-iL;
            iCurStartIndex = i;

            QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1

        }
    }

    // sub sort over f, which should be fast.
    // this step is to remain compliant with BuildNeighborsSlow() when
    // more than 2 triangles use the same edge (such as a butterfly topology).
    iCurStartIndex = 0;

    for (let i = 1; i < iEntries; i++) {

        if (
            pEdges[iCurStartIndex * 3] !== pEdges[i * 3]
            || pEdges[iCurStartIndex * 3 + 1] !== pEdges[i * 3 + 1]
        ) {
            const iL = iCurStartIndex;
            const iR = i - 1;
            //const int iElems = i-iL;
            iCurStartIndex = i;
            QuickSortEdges(pEdges, iL, iR, 2, uSeed);	// sort channel 2 which is f
        }

    }

    const temp_edge_A = vec3.create();
    const temp_edge_B = vec3.create();

    // pair up, adjacent triangles
    for (let i = 0; i < iEntries; i++) {

        const i0 = pEdges[i * 3];
        const i1 = pEdges[i * 3 + 1];
        const f = pEdges[i * 3 + 2];

        GetEdge(temp_edge_A, 0, piTriListIn, f * 3, i0, i1);	// resolve index ordering and edge_num

        const i0_A = temp_edge_A[0];
        const i1_A = temp_edge_A[1];
        const edgenum_A = temp_edge_A[2];

        const bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] === -1;

        if (!bUnassigned_A) {
            continue;
        }

        let j = i + 1;

        while (
            j < iEntries
            && i0 === pEdges[j * 3]
            && i1 === pEdges[j * 3 + 1]
            ) {

            const t = pEdges[j * 3 + 2];


            GetEdge(
                temp_edge_B,
                0,
                piTriListIn,
                t * 3,
                pEdges[j * 3],
                pEdges[j * 3 + 1]
            );	// resolve index ordering and edge_num

            // flip i0_B and i1_B
            const i0_B = temp_edge_B[1];
            const i1_B = temp_edge_B[2];
            const edgenum_B = temp_edge_B[2];

            //assert(!(i0_A==i1_B && i1_A==i0_B));
           const bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B] === -1;

            if (i0_A === i0_B && i1_A === i1_B && bUnassigned_B) {

                const t = pEdges[j * 3 + 2];
                pTriInfos[f].FaceNeighbors[edgenum_A] = t;
                //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1);
                pTriInfos[t].FaceNeighbors[edgenum_B] = f;
                break;

            } else {
                ++j;
            }
        }
    }
}
