function UnifiedSortWorker() {
		const myself = typeof self !== 'undefined' && self || require('node:worker_threads').parentPort;
		const centersMap = new Map();
		let centersData;
		let distances;
		let countBuffer;
		const evaluateSortKeys = (sortParams, minDist, divider, distances, countBuffer, centersData, bucketCount)=>{
				const { ids, lineStarts, padding, intervals, textureSize } = centersData;
				for(let paramIdx = 0; paramIdx < sortParams.length; paramIdx++){
						const params = sortParams[paramIdx];
						const { transformedDirection, offset, scale } = params;
						const dx = transformedDirection.x;
						const dy = transformedDirection.y;
						const dz = transformedDirection.z;
						const sdx = dx * scale * divider;
						const sdy = dy * scale * divider;
						const sdz = dz * scale * divider;
						const add = (offset - minDist) * divider;
						const id = ids[paramIdx];
						const centers = centersMap.get(id);
						if (!centers) {
								console.error('UnifiedSortWorker: No centers found for id', id);
						}
						let targetIndex = lineStarts[paramIdx] * textureSize;
						const intervalsArray = intervals[paramIdx].length > 0 ? intervals[paramIdx] : [
								0,
								centers.length / 3
						];
						for(let i = 0; i < intervalsArray.length; i += 2){
								const intervalStart = intervalsArray[i] * 3;
								const intervalEnd = intervalsArray[i + 1] * 3;
								for(let srcIndex = intervalStart; srcIndex < intervalEnd; srcIndex += 3){
										const x = centers[srcIndex];
										const y = centers[srcIndex + 1];
										const z = centers[srcIndex + 2];
										const sortKey = Math.floor(x * sdx + y * sdy + z * sdz + add);
										distances[targetIndex++] = sortKey;
										countBuffer[sortKey]++;
								}
						}
						const pad = padding[paramIdx];
						countBuffer[0] += pad;
						distances.fill(0, targetIndex, targetIndex + pad);
						targetIndex += pad;
				}
		};
		const countingSort = (bucketCount, countBuffer, numVertices, distances, order)=>{
				for(let i = 1; i < bucketCount; i++){
						countBuffer[i] += countBuffer[i - 1];
				}
				for(let i = 0; i < numVertices; i++){
						const distance = distances[i];
						const destIndex = --countBuffer[distance];
						order[destIndex] = i;
				}
		};
		const computeEffectiveDistanceRange = (sortParams)=>{
				let minDist = Infinity;
				let maxDist = -Infinity;
				for(let paramIdx = 0; paramIdx < sortParams.length; paramIdx++){
						const params = sortParams[paramIdx];
						const { transformedDirection, offset, scale, aabbMin, aabbMax } = params;
						const dx = transformedDirection.x;
						const dy = transformedDirection.y;
						const dz = transformedDirection.z;
						const pxMin = dx >= 0 ? aabbMin[0] : aabbMax[0];
						const pyMin = dy >= 0 ? aabbMin[1] : aabbMax[1];
						const pzMin = dz >= 0 ? aabbMin[2] : aabbMax[2];
						const pxMax = dx >= 0 ? aabbMax[0] : aabbMin[0];
						const pyMax = dy >= 0 ? aabbMax[1] : aabbMin[1];
						const pzMax = dz >= 0 ? aabbMax[2] : aabbMin[2];
						const dMin = pxMin * dx + pyMin * dy + pzMin * dz;
						const dMax = pxMax * dx + pyMax * dy + pzMax * dz;
						const eMin = dMin * scale + offset;
						const eMax = dMax * scale + offset;
						const localMin = Math.min(eMin, eMax);
						const localMax = Math.max(eMin, eMax);
						if (localMin < minDist) minDist = localMin;
						if (localMax > maxDist) maxDist = localMax;
				}
				if (minDist === Infinity) {
						minDist = 0;
						maxDist = 0;
				}
				return {
						minDist,
						maxDist
				};
		};
		const sort = (sortParams, order, centersData)=>{
				const { minDist, maxDist } = computeEffectiveDistanceRange(sortParams);
				const numVertices = centersData.totalUsedPixels;
				const compareBits = Math.max(10, Math.min(20, Math.round(Math.log2(numVertices / 4))));
				const bucketCount = 2 ** compareBits + 1;
				if (distances?.length !== numVertices) {
						distances = new Uint32Array(numVertices);
				}
				if (!countBuffer || countBuffer.length !== bucketCount) {
						countBuffer = new Uint32Array(bucketCount);
				} else {
						countBuffer.fill(0);
				}
				const range = maxDist - minDist;
				const divider = range < 1e-6 ? 0 : 1 / range * 2 ** compareBits;
				evaluateSortKeys(sortParams, minDist, divider, distances, countBuffer, centersData);
				countingSort(bucketCount, countBuffer, numVertices, distances, order);
				const count = numVertices;
				const transferList = [
						order.buffer
				];
				const response = {
						order: order.buffer,
						count,
						version: centersData.version
				};
				myself.postMessage(response, transferList);
		};
		myself.addEventListener('message', (message)=>{
				const msgData = message.data ?? message;
				switch(msgData.command){
						case 'addCenters':
								{
										centersMap.set(msgData.id, new Float32Array(msgData.centers));
										break;
								}
						case 'removeCenters':
								{
										centersMap.delete(msgData.id);
										break;
								}
						case 'sort':
								{
										const order = new Uint32Array(msgData.order);
										sort(msgData.sortParams, order, centersData);
										break;
								}
						case 'intervals':
								{
										centersData = msgData;
										break;
								}
				}
		});
}

export { UnifiedSortWorker };
