export type SpecialistModule = 'Points' | 'ReverseEngineering' | 'OpenSCAD' | 'Idf' | 'JtReader' | 'Material' | 'Import'
export type AdapterStatus = 'supported' | 'proxy' | 'unsupported'
export type DataAdapterDescriptor = { module: SpecialistModule; status: AdapterStatus; formats: string[]; operations: string[] }
export type DataRecord = { id: string; module: SpecialistModule; format: string; byteLength: number; proxy: boolean; metadata: Record<string, string> }
export type Point3 = { x: number; y: number; z: number }
export type PointCloudBounds = { min: Point3; max: Point3 }
export type StructuredPointCloud = { width: number; height: number; grid: (number | null)[] }
export type PointCloud = {
  id: string
  sourceFormat: PointCloudFormat | 'derived'
  units: 'mm' | 'm' | 'in'
  points: Point3[]
  bounds: PointCloudBounds
  centroid: Point3
  structured?: StructuredPointCloud
}
export type PointCloudFormat = 'asc' | 'pts' | 'xyz' | 'csv' | 'pcd' | 'ply'
export type Polygon2 = { x: number; y: number }
export type PlaneFitResult = { id: string; sourceId: string; kind: 'plane'; origin: Point3; normal: Point3; u: Point3; v: Point3; length: number; width: number; rms: number; pointCount: number }
export type SphereFitResult = { id: string; sourceId: string; kind: 'sphere'; center: Point3; radius: number; rms: number; pointCount: number }
export type CylinderFitResult = { id: string; sourceId: string; kind: 'cylinder'; base: Point3; axis: Point3; radius: number; height: number; rms: number; pointCount: number }
export type PolynomialFitResult = { id: string; sourceId: string; kind: 'polynomial-surface'; coefficients: [number, number, number, number, number, number]; rms: number; pointCount: number }
export type PointCloudSegment = { id: string; sourceId: string; radius: number; labels: number[]; clusters: { label: number; pointIndices: number[] }[] }
export type ReverseEngineeringResult = PlaneFitResult | SphereFitResult | CylinderFitResult | PolynomialFitResult
export type DataModulesSnapshot = { adapters: DataAdapterDescriptor[]; records: DataRecord[]; pointClouds: PointCloud[]; reverseEngineering: ReverseEngineeringResult[]; segments: PointCloudSegment[]; version: number }
export type DataModulesApi = {
  snapshot(): DataModulesSnapshot
  descriptors(): DataAdapterDescriptor[]
  importRecord(input: { id: string; module: SpecialistModule; format: string; bytes: ArrayLike<number>; metadata?: Record<string, string> }): DataRecord
  importPointCloud(input: { id: string; format: PointCloudFormat; bytes: ArrayLike<number>; units?: PointCloud['units']; translateToOrigin?: boolean; record?: boolean }): PointCloud
  exportPointCloud(id: string, format: PointCloudFormat): Uint8Array
  translatePointCloud(input: { id: string; sourceId: string; offset: Point3 }): PointCloud
  mergePointClouds(input: { id: string; sourceIds: string[] }): PointCloud
  cropPointCloud(input: { id: string; sourceId: string; bounds: PointCloudBounds }): PointCloud
  polygonCropPointCloud(input: { id: string; sourceId: string; polygon: Polygon2[]; invert?: boolean }): PointCloud
  voxelDownsample(input: { id: string; sourceId: string; size: number }): PointCloud
  structurePointCloud(input: { id: string; sourceId: string; tolerance?: number }): PointCloud
  fitPlane(input: { id: string; sourceId: string; referenceNormal?: Point3 }): PlaneFitResult
  fitSphere(input: { id: string; sourceId: string }): SphereFitResult
  fitCylinder(input: { id: string; sourceId: string }): CylinderFitResult
  fitPolynomialSurface(input: { id: string; sourceId: string }): PolynomialFitResult
  segmentPointCloud(input: { id: string; sourceId: string; radius: number }): PointCloudSegment
  removeRecord(id: string): void
  exportManifest(): string
}

const MAX_DATA_BYTES = 8 * 1024 * 1024
const MAX_POINT_COUNT = 1_000_000
const adapters: DataAdapterDescriptor[] = [
  { module: 'Points', status: 'supported', formats: ['asc', 'pts', 'xyz', 'csv', 'pcd', 'ply'], operations: ['import', 'export', 'translate', 'merge', 'crop', 'polygon-crop', 'structure', 'voxel-downsample'] },
  { module: 'ReverseEngineering', status: 'supported', formats: ['point-cloud'], operations: ['fit-plane', 'fit-sphere', 'fit-cylinder', 'fit-polynomial-surface', 'segment', 'report'] },
  { module: 'OpenSCAD', status: 'proxy', formats: ['scad'], operations: ['import', 'preview', 'export'] },
  { module: 'Idf', status: 'proxy', formats: ['idf'], operations: ['import', 'export'] },
  { module: 'JtReader', status: 'proxy', formats: ['jt'], operations: ['import', 'inspect'] },
  { module: 'Material', status: 'supported', formats: ['json', 'yaml'], operations: ['card', 'assign', 'export'] },
  { module: 'Import', status: 'supported', formats: ['step', 'iges', 'brep', 'stl', 'obj', 'dxf'], operations: ['import', 'batch', 'options'] },
]

const clone = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T
const descriptor = (module: SpecialistModule) => adapters.find((entry) => entry.module === module)!
const finite = (value: number, label: string) => {
  if (!Number.isFinite(value)) throw new RangeError(`${label} must be finite.`)
  return value
}
const point = (x: number, y: number, z: number): Point3 => ({ x: finite(x, 'Point x'), y: finite(y, 'Point y'), z: finite(z, 'Point z') })
const add = (a: Point3, b: Point3): Point3 => point(a.x + b.x, a.y + b.y, a.z + b.z)
const subtract = (a: Point3, b: Point3): Point3 => point(a.x - b.x, a.y - b.y, a.z - b.z)
const scale = (a: Point3, value: number): Point3 => point(a.x * value, a.y * value, a.z * value)
const dot = (a: Point3, b: Point3) => a.x * b.x + a.y * b.y + a.z * b.z
const cross = (a: Point3, b: Point3): Point3 => point(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x)
const length = (value: Point3) => Math.hypot(value.x, value.y, value.z)
const normalize = (value: Point3, label: string): Point3 => {
  const magnitude = length(value)
  if (!Number.isFinite(magnitude) || magnitude <= 1e-12) throw new RangeError(`${label} must have non-zero length.`)
  return scale(value, 1 / magnitude)
}
const stableDirection = (value: Point3): Point3 => {
  const direction = normalize(value, 'Direction')
  const components = [direction.x, direction.y, direction.z]
  let dominant = 0
  for (let index = 1; index < components.length; index += 1) if (Math.abs(components[index]) > Math.abs(components[dominant])) dominant = index
  return components[dominant] < 0 ? scale(direction, -1) : direction
}
const validateBounds = (bounds: PointCloudBounds) => {
  const min = point(bounds.min.x, bounds.min.y, bounds.min.z)
  const max = point(bounds.max.x, bounds.max.y, bounds.max.z)
  if (min.x > max.x || min.y > max.y || min.z > max.z) throw new RangeError('Point-cloud bounds must be ordered on every axis.')
  return { min, max }
}
const summarizePoints = (points: Point3[]): Pick<PointCloud, 'bounds' | 'centroid'> => {
  if (points.length === 0) throw new RangeError('Point cloud must contain at least one point.')
  if (points.length > MAX_POINT_COUNT) throw new RangeError(`Point cloud exceeds ${MAX_POINT_COUNT} points.`)
  const min = { ...points[0] }; const max = { ...points[0] }; const sum = { x: 0, y: 0, z: 0 }
  for (const entry of points) {
    point(entry.x, entry.y, entry.z)
    min.x = Math.min(min.x, entry.x); min.y = Math.min(min.y, entry.y); min.z = Math.min(min.z, entry.z)
    max.x = Math.max(max.x, entry.x); max.y = Math.max(max.y, entry.y); max.z = Math.max(max.z, entry.z)
    sum.x += entry.x; sum.y += entry.y; sum.z += entry.z
  }
  return { bounds: { min, max }, centroid: scale(sum, 1 / points.length) }
}
const decode = (bytes: ArrayLike<number>) => {
  if (!Number.isSafeInteger(bytes.length) || bytes.length <= 0 || bytes.length > MAX_DATA_BYTES) throw new RangeError('Data record byte length is outside the supported limit.')
  try { return new TextDecoder('utf-8', { fatal: true }).decode(Uint8Array.from(bytes)) } catch { throw new RangeError('Point cloud must be valid UTF-8 text.') }
}
const numericColumns = (line: string, comma: boolean) => (comma ? line.split(',') : line.trim().split(/[\s,;]+/)).map((value) => value.trim())
const parseTriples = (lines: string[], comma = false) => {
  const points: Point3[] = []
  for (const line of lines) {
    const trimmed = line.trim()
    if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('//')) continue
    const values = numericColumns(trimmed, comma)
    if (values.length < 3) throw new RangeError(`Point row must contain x, y and z: ${trimmed}`)
    const xyz = values.slice(0, 3).map(Number)
    if (xyz.some((value) => !Number.isFinite(value))) {
      if (points.length === 0 && values.slice(0, 3).map((value) => value.toLowerCase()).join(',') === 'x,y,z') continue
      throw new RangeError(`Point row contains a non-numeric coordinate: ${trimmed}`)
    }
    points.push(point(xyz[0], xyz[1], xyz[2]))
    if (points.length > MAX_POINT_COUNT) throw new RangeError(`Point cloud exceeds ${MAX_POINT_COUNT} points.`)
  }
  return points
}
const parsePcd = (text: string) => {
  const lines = text.split(/\r?\n/); const dataIndex = lines.findIndex((line) => /^DATA\s+/i.test(line.trim()))
  if (dataIndex < 0 || !/^DATA\s+ascii$/i.test(lines[dataIndex].trim())) throw new RangeError('Only ASCII PCD point clouds are supported.')
  const fieldsLine = lines.slice(0, dataIndex).find((line) => /^FIELDS\s+/i.test(line.trim()))
  if (!fieldsLine) throw new RangeError('PCD FIELDS header is required.')
  const fields = fieldsLine.trim().split(/\s+/).slice(1).map((value) => value.toLowerCase())
  const indexes = ['x', 'y', 'z'].map((field) => fields.indexOf(field))
  if (indexes.some((index) => index < 0)) throw new RangeError('PCD must declare x, y and z fields.')
  return lines.slice(dataIndex + 1).filter((line) => line.trim()).map((line) => {
    const values = line.trim().split(/\s+/).map(Number)
    return point(values[indexes[0]], values[indexes[1]], values[indexes[2]])
  })
}
const parsePly = (text: string) => {
  const lines = text.split(/\r?\n/)
  if (lines[0]?.trim() !== 'ply' || !lines.some((line) => line.trim() === 'format ascii 1.0')) throw new RangeError('Only ASCII PLY point clouds are supported.')
  const end = lines.findIndex((line) => line.trim() === 'end_header')
  if (end < 0) throw new RangeError('PLY end_header is required.')
  const vertexLine = lines.slice(0, end).find((line) => /^element\s+vertex\s+/i.test(line.trim()))
  const count = Number(vertexLine?.trim().split(/\s+/)[2])
  if (!Number.isSafeInteger(count) || count <= 0 || count > MAX_POINT_COUNT) throw new RangeError('PLY vertex count is outside the supported limit.')
  const properties: string[] = []
  let inVertex = false
  for (const line of lines.slice(0, end)) {
    const trimmed = line.trim()
    if (/^element\s+vertex\s+/i.test(trimmed)) { inVertex = true; continue }
    if (/^element\s+/i.test(trimmed)) inVertex = false
    if (inVertex && /^property\s+/i.test(trimmed)) properties.push(trimmed.split(/\s+/).at(-1)!.toLowerCase())
  }
  const indexes = ['x', 'y', 'z'].map((field) => properties.indexOf(field))
  if (indexes.some((index) => index < 0)) throw new RangeError('PLY vertices must declare x, y and z properties.')
  const rows = lines.slice(end + 1, end + 1 + count)
  if (rows.length !== count) throw new RangeError('PLY contains fewer vertices than declared.')
  return rows.map((line) => { const values = line.trim().split(/\s+/).map(Number); return point(values[indexes[0]], values[indexes[1]], values[indexes[2]]) })
}
const parsePointCloud = (format: PointCloudFormat, bytes: ArrayLike<number>) => {
  const text = decode(bytes); const lines = text.split(/\r?\n/)
  if (format === 'pcd') return parsePcd(text)
  if (format === 'ply') return parsePly(text)
  if (format === 'pts') {
    const first = lines.findIndex((line) => line.trim() && !line.trim().startsWith('#'))
    const declared = first >= 0 && /^\d+$/.test(lines[first].trim()) ? Number(lines[first].trim()) : null
    const points = parseTriples(declared === null ? lines : lines.filter((_, index) => index !== first))
    if (declared !== null && points.length !== declared) throw new RangeError(`PTS declared ${declared} points but contains ${points.length}.`)
    return points
  }
  return parseTriples(lines, format === 'csv')
}
const formatNumber = (value: number) => Object.is(value, -0) ? '0' : Number(value.toPrecision(15)).toString()
const exportPointText = (cloud: PointCloud, format: PointCloudFormat) => {
  const rows = cloud.points.map(({ x, y, z }) => `${formatNumber(x)}${format === 'csv' ? ',' : ' '}${formatNumber(y)}${format === 'csv' ? ',' : ' '}${formatNumber(z)}`)
  if (format === 'pts') return `${cloud.points.length}\n${rows.join('\n')}\n`
  if (format === 'csv') return `x,y,z\n${rows.join('\n')}\n`
  if (format === 'pcd') return `# .PCD v0.7\nVERSION 0.7\nFIELDS x y z\nSIZE 4 4 4\nTYPE F F F\nCOUNT 1 1 1\nWIDTH ${cloud.points.length}\nHEIGHT 1\nVIEWPOINT 0 0 0 1 0 0 0\nPOINTS ${cloud.points.length}\nDATA ascii\n${rows.join('\n')}\n`
  if (format === 'ply') return `ply\nformat ascii 1.0\nelement vertex ${cloud.points.length}\nproperty double x\nproperty double y\nproperty double z\nend_header\n${rows.join('\n')}\n`
  return `${rows.join('\n')}\n`
}
const covariance = (points: Point3[], center: Point3) => {
  const matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
  for (const entry of points) {
    const values = [entry.x - center.x, entry.y - center.y, entry.z - center.z]
    for (let row = 0; row < 3; row += 1) for (let column = row; column < 3; column += 1) matrix[row][column] += values[row] * values[column]
  }
  for (let row = 0; row < 3; row += 1) for (let column = row; column < 3; column += 1) matrix[row][column] = matrix[column][row] = matrix[row][column] / points.length
  return matrix
}
const symmetricEigenvectors = (input: number[][]) => {
  const matrix = input.map((row) => [...row]); const vectors = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
  for (let iteration = 0; iteration < 32; iteration += 1) {
    let p = 0; let q = 1
    for (const [row, column] of [[0, 1], [0, 2], [1, 2]]) if (Math.abs(matrix[row][column]) > Math.abs(matrix[p][q])) { p = row; q = column }
    if (Math.abs(matrix[p][q]) < 1e-14) break
    const angle = 0.5 * Math.atan2(2 * matrix[p][q], matrix[q][q] - matrix[p][p]); const cosine = Math.cos(angle); const sine = Math.sin(angle)
    for (let index = 0; index < 3; index += 1) {
      const mip = matrix[index][p]; const miq = matrix[index][q]
      matrix[index][p] = cosine * mip - sine * miq; matrix[index][q] = sine * mip + cosine * miq
    }
    for (let index = 0; index < 3; index += 1) {
      const mpi = matrix[p][index]; const mqi = matrix[q][index]
      matrix[p][index] = cosine * mpi - sine * mqi; matrix[q][index] = sine * mpi + cosine * mqi
      const vip = vectors[index][p]; const viq = vectors[index][q]
      vectors[index][p] = cosine * vip - sine * viq; vectors[index][q] = sine * vip + cosine * viq
    }
  }
  return [0, 1, 2].map((index) => ({ value: matrix[index][index], vector: stableDirection(point(vectors[0][index], vectors[1][index], vectors[2][index])) })).sort((a, b) => a.value - b.value)
}
const solveLinear = (matrix: number[][], values: number[]) => {
  const size = values.length; const augmented = matrix.map((row, index) => [...row, values[index]])
  for (let column = 0; column < size; column += 1) {
    let pivot = column
    for (let row = column + 1; row < size; row += 1) if (Math.abs(augmented[row][column]) > Math.abs(augmented[pivot][column])) pivot = row
    if (Math.abs(augmented[pivot][column]) < 1e-12) throw new RangeError('Point set is degenerate for the requested fit.')
    ;[augmented[column], augmented[pivot]] = [augmented[pivot], augmented[column]]
    const divisor = augmented[column][column]
    for (let index = column; index <= size; index += 1) augmented[column][index] /= divisor
    for (let row = 0; row < size; row += 1) if (row !== column) {
      const factor = augmented[row][column]
      for (let index = column; index <= size; index += 1) augmented[row][index] -= factor * augmented[column][index]
    }
  }
  return augmented.map((row) => row[size])
}
const leastSquares = (rows: number[][], values: number[]) => {
  const size = rows[0].length; const normal = Array.from({ length: size }, () => Array(size).fill(0)); const rhs = Array(size).fill(0)
  for (let index = 0; index < rows.length; index += 1) for (let row = 0; row < size; row += 1) {
    rhs[row] += rows[index][row] * values[index]
    for (let column = 0; column < size; column += 1) normal[row][column] += rows[index][row] * rows[index][column]
  }
  return solveLinear(normal, rhs)
}
const fitCircle2d = (points: { x: number; y: number }[]) => {
  if (points.length < 3) throw new RangeError('Cylinder fit requires at least three points.')
  const solution = leastSquares(points.map(({ x, y }) => [2 * x, 2 * y, 1]), points.map(({ x, y }) => x * x + y * y))
  const center = { x: solution[0], y: solution[1] }; const distances = points.map(({ x, y }) => Math.hypot(x - center.x, y - center.y)); const radius = distances.reduce((sum, value) => sum + value, 0) / distances.length
  return { center, radius, rms: Math.sqrt(distances.reduce((sum, value) => sum + (value - radius) ** 2, 0) / distances.length) }
}
const pointInPolygon = (entry: Point3, polygon: Polygon2[]) => {
  let inside = false
  for (let index = 0, previous = polygon.length - 1; index < polygon.length; previous = index++) {
    const current = polygon[index]; const prior = polygon[previous]
    const crosses = (current.y > entry.y) !== (prior.y > entry.y)
    if (crosses && entry.x < ((prior.x - current.x) * (entry.y - current.y)) / (prior.y - current.y) + current.x) inside = !inside
  }
  return inside
}
const polygonArea = (polygon: Polygon2[]) => polygon.reduce((sum, current, index) => { const previous = polygon[(index + polygon.length - 1) % polygon.length]; return sum + previous.x * current.y - current.x * previous.y }, 0) / 2

export const createDataModules = (): DataModulesApi => {
  const records = new Map<string, DataRecord>(); const pointClouds = new Map<string, PointCloud>(); const results = new Map<string, ReverseEngineeringResult>(); const segments = new Map<string, PointCloudSegment>(); let version = 0
  const snapshot = (): DataModulesSnapshot => ({ adapters: clone(adapters), records: [...records.values()].map(clone), pointClouds: [...pointClouds.values()].map(clone), reverseEngineering: [...results.values()].map(clone), segments: [...segments.values()].map(clone), version })
  const ensureNewCloudId = (id: string) => { if (!id.trim() || pointClouds.has(id)) throw new RangeError(`Point cloud already exists: ${id}`) }
  const sourceCloud = (id: string) => { const cloud = pointClouds.get(id); if (!cloud) throw new RangeError(`Point cloud does not exist: ${id}`); return cloud }
  const storeCloud = (id: string, points: Point3[], units: PointCloud['units'], sourceFormat: PointCloud['sourceFormat'], structured?: StructuredPointCloud) => {
    ensureNewCloudId(id); const summary = summarizePoints(points); const cloud: PointCloud = { id, sourceFormat, units, points: points.map((entry) => ({ ...entry })), ...summary, ...(structured ? { structured } : {}) }
    pointClouds.set(id, cloud); version += 1; return clone(cloud)
  }
  const storeResult = <T extends ReverseEngineeringResult>(result: T) => { if (!result.id.trim() || results.has(result.id)) throw new RangeError(`Reverse-engineering result already exists: ${result.id}`); results.set(result.id, result); version += 1; return clone(result) }
  const importRecord = (input: { id: string; module: SpecialistModule; format: string; bytes: ArrayLike<number>; metadata?: Record<string, string> }) => {
    const selected = descriptor(input.module)
    if (!input.id.trim() || records.has(input.id)) throw new RangeError(`Data record already exists: ${input.id}`)
    if (!selected.formats.includes(input.format.toLowerCase())) throw new RangeError(`${input.module} does not accept format ${input.format}.`)
    if (!Number.isSafeInteger(input.bytes.length) || input.bytes.length <= 0 || input.bytes.length > MAX_DATA_BYTES) throw new RangeError('Data record byte length is outside the supported limit.')
    const record: DataRecord = { id: input.id, module: input.module, format: input.format.toLowerCase(), byteLength: input.bytes.length, proxy: selected.status !== 'supported', metadata: { ...(input.metadata || {}) } }
    records.set(record.id, record); version += 1; return clone(record)
  }
  const importPointCloud: DataModulesApi['importPointCloud'] = (input) => {
    if (records.has(input.id)) throw new RangeError(`Data record already exists: ${input.id}`)
    const parsed = parsePointCloud(input.format, input.bytes); const summary = summarizePoints(parsed)
    const translated = input.translateToOrigin ? parsed.map((entry) => subtract(entry, summary.centroid)) : parsed
    const cloud = storeCloud(input.id, translated, input.units || 'mm', input.format)
    if (input.record !== false) records.set(input.id, { id: input.id, module: 'Points', format: input.format, byteLength: input.bytes.length, proxy: false, metadata: { units: cloud.units, points: String(cloud.points.length) } })
    return cloud
  }
  const translatePointCloud: DataModulesApi['translatePointCloud'] = ({ id, sourceId, offset }) => { const source = sourceCloud(sourceId); const validOffset = point(offset.x, offset.y, offset.z); return storeCloud(id, source.points.map((entry) => add(entry, validOffset)), source.units, 'derived', source.structured ? clone(source.structured) : undefined) }
  const mergePointClouds: DataModulesApi['mergePointClouds'] = ({ id, sourceIds }) => {
    if (sourceIds.length < 2 || new Set(sourceIds).size !== sourceIds.length) throw new RangeError('Point-cloud merge requires at least two unique sources.')
    const sources = sourceIds.map(sourceCloud); if (sources.some((source) => source.units !== sources[0].units)) throw new RangeError('Point-cloud merge requires matching units.')
    return storeCloud(id, sources.flatMap((source) => source.points), sources[0].units, 'derived')
  }
  const cropPointCloud: DataModulesApi['cropPointCloud'] = ({ id, sourceId, bounds }) => {
    const source = sourceCloud(sourceId); const valid = validateBounds(bounds); const filtered = source.points.filter(({ x, y, z }) => x >= valid.min.x && x <= valid.max.x && y >= valid.min.y && y <= valid.max.y && z >= valid.min.z && z <= valid.max.z)
    if (filtered.length === 0) throw new RangeError('Point-cloud crop removed every point.')
    return storeCloud(id, filtered, source.units, 'derived')
  }
  const polygonCropPointCloud: DataModulesApi['polygonCropPointCloud'] = ({ id, sourceId, polygon, invert = false }) => {
    const source = sourceCloud(sourceId); const vertices = polygon.map((entry) => ({ x: finite(entry.x, 'Polygon x'), y: finite(entry.y, 'Polygon y') })); if (vertices.length < 3 || Math.abs(polygonArea(vertices)) <= 1e-12) throw new RangeError('Polygon crop requires a non-degenerate polygon.')
    const filtered = source.points.filter((entry) => pointInPolygon(entry, vertices) !== invert); if (filtered.length === 0) throw new RangeError('Point-cloud polygon crop removed every point.')
    return storeCloud(id, filtered, source.units, 'derived')
  }
  const voxelDownsample: DataModulesApi['voxelDownsample'] = ({ id, sourceId, size }) => {
    const source = sourceCloud(sourceId); finite(size, 'Voxel size'); if (size <= 0) throw new RangeError('Voxel size must be positive.')
    const cells = new Map<string, { sum: Point3; count: number }>()
    for (const entry of source.points) { const key = `${Math.floor(entry.x / size)}:${Math.floor(entry.y / size)}:${Math.floor(entry.z / size)}`; const cell = cells.get(key) || { sum: { x: 0, y: 0, z: 0 }, count: 0 }; cell.sum = add(cell.sum, entry); cell.count += 1; cells.set(key, cell) }
    const reduced = [...cells.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([, cell]) => scale(cell.sum, 1 / cell.count))
    return storeCloud(id, reduced, source.units, 'derived')
  }
  const structurePointCloud: DataModulesApi['structurePointCloud'] = ({ id, sourceId, tolerance = 1e-6 }) => {
    const source = sourceCloud(sourceId); finite(tolerance, 'Structure tolerance'); if (tolerance <= 0) throw new RangeError('Structure tolerance must be positive.')
    const unique = (values: number[]) => [...values].sort((a, b) => a - b).filter((value, index, sorted) => index === 0 || Math.abs(value - sorted[index - 1]) > tolerance)
    const xs = unique(source.points.map((entry) => entry.x)); const ys = unique(source.points.map((entry) => entry.y))
    if (xs.length < 2 || ys.length < 2) throw new RangeError('Structured point cloud requires at least two rows and columns.')
    const sorted = [...source.points].sort((a, b) => a.y - b.y || a.x - b.x || a.z - b.z); const grid: (number | null)[] = Array(xs.length * ys.length).fill(null)
    sorted.forEach((entry, index) => { const x = xs.findIndex((value) => Math.abs(value - entry.x) <= tolerance); const y = ys.findIndex((value) => Math.abs(value - entry.y) <= tolerance); const slot = y * xs.length + x; if (x < 0 || y < 0 || grid[slot] !== null) throw new RangeError('Point cloud cannot be represented as a unique XY grid.'); grid[slot] = index })
    return storeCloud(id, sorted, source.units, 'derived', { width: xs.length, height: ys.length, grid })
  }
  const fitPlane: DataModulesApi['fitPlane'] = ({ id, sourceId, referenceNormal }) => {
    const source = sourceCloud(sourceId); if (source.points.length < 3) throw new RangeError('Plane fit requires at least three points.')
    const eigen = symmetricEigenvectors(covariance(source.points, source.centroid)); if (eigen[1].value <= 1e-14) throw new RangeError('Point set is degenerate for the requested plane fit.'); let normal = eigen[0].vector
    if (referenceNormal && dot(normal, normalize(referenceNormal, 'Reference normal')) < 0) normal = scale(normal, -1)
    let u = eigen[2].vector; if (Math.abs(dot(u, normal)) > 1e-8) u = normalize(cross(Math.abs(normal.z) < 0.9 ? { x: 0, y: 0, z: 1 } : { x: 0, y: 1, z: 0 }, normal), 'Plane u axis')
    const v = normalize(cross(normal, u), 'Plane v axis'); const coordinates = source.points.map((entry) => { const relative = subtract(entry, source.centroid); return { u: dot(relative, u), v: dot(relative, v), n: dot(relative, normal) } })
    const minU = Math.min(...coordinates.map((entry) => entry.u)); const maxU = Math.max(...coordinates.map((entry) => entry.u)); const minV = Math.min(...coordinates.map((entry) => entry.v)); const maxV = Math.max(...coordinates.map((entry) => entry.v))
    return storeResult({ id, sourceId, kind: 'plane', origin: add(add(source.centroid, scale(u, minU)), scale(v, minV)), normal, u, v, length: maxU - minU, width: maxV - minV, rms: Math.sqrt(coordinates.reduce((sum, entry) => sum + entry.n ** 2, 0) / coordinates.length), pointCount: source.points.length })
  }
  const fitSphere: DataModulesApi['fitSphere'] = ({ id, sourceId }) => {
    const source = sourceCloud(sourceId); if (source.points.length < 4) throw new RangeError('Sphere fit requires at least four points.')
    const solution = leastSquares(source.points.map(({ x, y, z }) => [2 * x, 2 * y, 2 * z, 1]), source.points.map(({ x, y, z }) => x * x + y * y + z * z)); const center = point(solution[0], solution[1], solution[2]); const distances = source.points.map((entry) => length(subtract(entry, center))); const radius = distances.reduce((sum, value) => sum + value, 0) / distances.length
    return storeResult({ id, sourceId, kind: 'sphere', center, radius, rms: Math.sqrt(distances.reduce((sum, value) => sum + (value - radius) ** 2, 0) / distances.length), pointCount: source.points.length })
  }
  const fitCylinder: DataModulesApi['fitCylinder'] = ({ id, sourceId }) => {
    const source = sourceCloud(sourceId); if (source.points.length < 6) throw new RangeError('Cylinder fit requires at least six points.')
    const axis = symmetricEigenvectors(covariance(source.points, source.centroid))[2].vector; const seed = Math.abs(axis.z) < 0.9 ? { x: 0, y: 0, z: 1 } : { x: 0, y: 1, z: 0 }; const u = normalize(cross(seed, axis), 'Cylinder u axis'); const v = normalize(cross(axis, u), 'Cylinder v axis')
    const projected = source.points.map((entry) => { const relative = subtract(entry, source.centroid); return { x: dot(relative, u), y: dot(relative, v), axial: dot(relative, axis) } }); const circle = fitCircle2d(projected); const min = Math.min(...projected.map((entry) => entry.axial)); const max = Math.max(...projected.map((entry) => entry.axial)); const center = add(add(source.centroid, scale(u, circle.center.x)), scale(v, circle.center.y)); const base = add(center, scale(axis, min))
    return storeResult({ id, sourceId, kind: 'cylinder', base, axis, radius: circle.radius, height: max - min, rms: circle.rms, pointCount: source.points.length })
  }
  const fitPolynomialSurface: DataModulesApi['fitPolynomialSurface'] = ({ id, sourceId }) => {
    const source = sourceCloud(sourceId); if (source.points.length < 6) throw new RangeError('Polynomial surface fit requires at least six points.')
    const solution = leastSquares(source.points.map(({ x, y }) => [x * x, x * y, y * y, x, y, 1]), source.points.map(({ z }) => z)) as [number, number, number, number, number, number]
    const residuals = source.points.map(({ x, y, z }) => z - (solution[0] * x * x + solution[1] * x * y + solution[2] * y * y + solution[3] * x + solution[4] * y + solution[5]))
    return storeResult({ id, sourceId, kind: 'polynomial-surface', coefficients: solution, rms: Math.sqrt(residuals.reduce((sum, value) => sum + value * value, 0) / residuals.length), pointCount: source.points.length })
  }
  const segmentPointCloud: DataModulesApi['segmentPointCloud'] = ({ id, sourceId, radius }) => {
    const source = sourceCloud(sourceId); finite(radius, 'Segmentation radius'); if (radius <= 0) throw new RangeError('Segmentation radius must be positive.'); if (source.points.length > 50_000) throw new RangeError('Segmentation is limited to 50000 points in the browser subset.')
    const cellSize = radius; const cells = new Map<string, number[]>(); const keyFor = (entry: Point3) => `${Math.floor(entry.x / cellSize)}:${Math.floor(entry.y / cellSize)}:${Math.floor(entry.z / cellSize)}`
    source.points.forEach((entry, index) => { const key = keyFor(entry); const values = cells.get(key) || []; values.push(index); cells.set(key, values) })
    const labels = Array(source.points.length).fill(-1); const clusters: { label: number; pointIndices: number[] }[] = []; const radiusSquared = radius * radius
    for (let start = 0; start < source.points.length; start += 1) if (labels[start] < 0) {
      const label = clusters.length; const queue = [start]; const pointIndices: number[] = []; labels[start] = label
      for (let cursor = 0; cursor < queue.length; cursor += 1) {
        const currentIndex = queue[cursor]; const current = source.points[currentIndex]; pointIndices.push(currentIndex); const baseX = Math.floor(current.x / cellSize); const baseY = Math.floor(current.y / cellSize); const baseZ = Math.floor(current.z / cellSize)
        for (let dx = -1; dx <= 1; dx += 1) for (let dy = -1; dy <= 1; dy += 1) for (let dz = -1; dz <= 1; dz += 1) for (const candidate of cells.get(`${baseX + dx}:${baseY + dy}:${baseZ + dz}`) || []) if (labels[candidate] < 0) {
          const other = source.points[candidate]; const delta = subtract(other, current); if (dot(delta, delta) <= radiusSquared) { labels[candidate] = label; queue.push(candidate) }
        }
      }
      clusters.push({ label, pointIndices })
    }
    const result: PointCloudSegment = { id, sourceId, radius, labels, clusters }; if (segments.has(id)) throw new RangeError(`Segmentation result already exists: ${id}`); segments.set(id, result); version += 1; return clone(result)
  }
  const removeRecord = (id: string) => { if (!records.delete(id)) throw new RangeError(`Data record does not exist: ${id}`); pointClouds.delete(id); for (const [resultId, result] of results) if (result.sourceId === id) results.delete(resultId); for (const [segmentId, segment] of segments) if (segment.sourceId === id) segments.delete(segmentId); version += 1 }
  const exportManifest = () => `${JSON.stringify(snapshot(), null, 2)}\n`
  return { snapshot, descriptors: () => clone(adapters), importRecord, importPointCloud, exportPointCloud: (id, format) => new TextEncoder().encode(exportPointText(sourceCloud(id), format)), translatePointCloud, mergePointClouds, cropPointCloud, polygonCropPointCloud, voxelDownsample, structurePointCloud, fitPlane, fitSphere, fitCylinder, fitPolynomialSurface, segmentPointCloud, removeRecord, exportManifest }
}
