/**
 * 视锥内点云管理工具
 * 从 robot_map_editor 移植
 * 
 * 功能：根据相机视锥范围动态加载/卸载点云
 * 优化性能，只渲染可见区域的点云
 */

import * as THREE from 'three'

// 最大显示帧数（视锥内）
const maxFrame = 100

// 当前显示的索引列表
let currentShowIndex = []

/**
 * 稀释数组（按间隔抽取）
 * @param {Array} arr - 原数组
 * @param {number} distance - 间隔距离
 * @returns {Array} 稀释后的数组
 */
const thinArrayByDistance = (arr, distance) => {
  return arr.filter((_, index) => index % (distance + 1) === 0)
}

/**
 * 数值范围映射（用于颜色插值）
 * @param {number} val - 输入值
 * @param {number} min - 最小值
 * @param {number} max - 最大值
 * @returns {number} 映射到 0-1 范围
 */
const getRangeNumber = (val, min, max) => {
  if (val < 0) {
    return Number.parseFloat(
      Math.abs(Math.abs(val) + min) / (max - min)
    ).toFixed(1)
  } else if (val === 0) {
    return Number.parseFloat((val - min) / (max - min)).toFixed(1)
  } else {
    return Number.parseFloat((val - min) / (max - min)).toFixed(1)
  }
}

/**
 * 线性插值颜色
 * @param {Array} origin - 起始颜色 [r,g,b]
 * @param {Array} color - 目标颜色 [r,g,b]
 * @param {number} alpha - 插值系数 0-1
 * @returns {Array} 插值后的颜色 [r,g,b]
 */
const lerp = (origin, color, alpha) => {
  const r = origin[0] + (color[0] - origin[0]) * alpha
  const g = origin[1] + (color[1] - origin[1]) * alpha
  const b = origin[2] + (color[2] - origin[2]) * alpha
  return [r, g, b]
}

/**
 * 创建点云（批量）
 * @param {THREE.Group} newPointsGroup - 点云组
 * @param {Array} addPointsIndexs - 要添加的点云索引
 * @param {Array} cloudArry - 点云数据数组
 * @param {Array} gTransArry - 变换矩阵数组
 */
const createPoints = (newPointsGroup, addPointsIndexs, cloudArry, gTransArry) => {
  // 高度颜色映射
  const color1 = [0, 0, 1]    // 蓝色
  const color2 = [0, 1, 0]    // 绿色
  const color3 = [1, 1, 0]    // 黄色
  const color4 = [1, 0, 0]    // 红色
  
  for (let index = 0; index < addPointsIndexs.length; index++) {
    const currentIndex = addPointsIndexs[index]
    const currentCloud = cloudArry[currentIndex]
    const transMatrix = gTransArry[currentIndex]
    
    if (!currentCloud || !transMatrix) continue
    
    const pointsList = currentCloud.pointsList
    const positions = new Float32Array(pointsList.length * 3)
    const colors = new Float32Array(pointsList.length * 3)
    
    // 坐标变换 + 颜色映射
    for (let i = 0; i < pointsList.length; i++) {
      // 应用变换矩阵：传感器坐标 → 世界坐标
      positions[i * 3] =
        pointsList[i].x * transMatrix.r11 +
        pointsList[i].y * transMatrix.r12 +
        pointsList[i].z * transMatrix.r13 +
        transMatrix.tx
        
      positions[i * 3 + 1] =
        pointsList[i].x * transMatrix.r21 +
        pointsList[i].y * transMatrix.r22 +
        pointsList[i].z * transMatrix.r23 +
        transMatrix.ty
        
      positions[i * 3 + 2] =
        pointsList[i].x * transMatrix.r31 +
        pointsList[i].y * transMatrix.r32 +
        pointsList[i].z * transMatrix.r33 +
        transMatrix.tz

      // 根据高度映射颜色
      const positonZ = positions[i * 3 + 2]
      
      if (positonZ < -1) {
        // 蓝色
        colors[i * 3] = color1[0]
        colors[i * 3 + 1] = color1[1]
        colors[i * 3 + 2] = color1[2]
        
      } else if (-1 <= positonZ && positonZ < 5) {
        // 蓝→绿渐变
        const percent = getRangeNumber(positonZ, -1, 5)
        const c = lerp(color1, color2, percent)
        colors[i * 3] = c[0]
        colors[i * 3 + 1] = c[1]
        colors[i * 3 + 2] = c[2]
        
      } else if (5 <= positonZ && positonZ < 10) {
        // 绿→黄渐变
        const percent = getRangeNumber(positonZ, 5, 10)
        const c = lerp(color2, color3, percent)
        colors[i * 3] = c[0]
        colors[i * 3 + 1] = c[1]
        colors[i * 3 + 2] = c[2]
        
      } else if (10 <= positonZ && positonZ < 15) {
        // 黄→红渐变
        const percent = getRangeNumber(positonZ, 10, 15)
        const c = lerp(color3, color4, percent)
        colors[i * 3] = c[0]
        colors[i * 3 + 1] = c[1]
        colors[i * 3 + 2] = c[2]
        
      } else {
        // 红色
        colors[i * 3] = color4[0]
        colors[i * 3 + 1] = color4[1]
        colors[i * 3 + 2] = color4[2]
      }
    }
    
    // 创建点云几何体
    const geometry = new THREE.BufferGeometry()
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
    
    // 创建 ShaderMaterial 定义渲染方式（参考 robot_map_editor）
    const material = new THREE.ShaderMaterial({
      vertexShader: `
        attribute vec3 color;
        varying vec3 vColor;

        void main() {
            vColor = color;
            gl_PointSize = 0.8;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `,
      fragmentShader: `
        varying vec3 vColor;

        void main() {
            gl_FragColor = vec4(vColor, 1.0);
        }
      `
    })
    
    const object = new THREE.Points(geometry, material)
    object.transIndex = currentIndex
    newPointsGroup.add(object)
  }
}

/**
 * 创建视锥内的点云网格
 * 主函数：根据视锥范围动态管理点云显示
 * 
 * @param {THREE.Group} newPointsGroup - 点云组
 * @param {Array} intersectingIndex - 当前视锥内的索引列表
 * @param {Array} cloudArry - 所有点云数据
 * @param {Array} gTransArry - 所有变换矩阵
 */
export default function createIntersectPointsMesh(
  newPointsGroup, 
  intersectingIndex, 
  cloudArry, 
  gTransArry
) {
  const pointsMesh = newPointsGroup.children
  
  if (currentShowIndex.length === 0) {
    // 首次初始化
    currentShowIndex = intersectingIndex
    return
  }
  
  // 复制一份以便处理
  let machinedIntersectingIndex = [...intersectingIndex]
  
  // 如果视锥内点云超过最大帧数，进行稀释
  if (machinedIntersectingIndex.length > maxFrame) {
    const distance = Math.ceil(intersectingIndex.length / maxFrame)
    machinedIntersectingIndex = thinArrayByDistance(intersectingIndex, distance)
  }
  
  // 找出需要删除的点云（不在新索引中的旧索引）
  const removeIndexs = currentShowIndex.filter(
    value => !machinedIntersectingIndex.includes(value)
  )
  
  // 删除点云
  if (removeIndexs && removeIndexs.length > 0) {
    for (let i = 0; i < removeIndexs.length; i++) {
      const element = removeIndexs[i]
      const findMesh = pointsMesh.find((item) => {
        return item.transIndex === element
      })
      
      if (findMesh) {
        findMesh.geometry.dispose()  // 释放几何体
        findMesh.material.dispose()  // 释放材质
        findMesh.clear()              // 清空对象
        newPointsGroup.remove(findMesh)
      }
    }
  }
  
  // 找出需要添加的点云（新索引中不在旧索引的）
  const addPointsIndexs = machinedIntersectingIndex.filter(
    value => !currentShowIndex.includes(value)
  )
  
  // 创建新点云
  if (addPointsIndexs.length > 0) {
    createPoints(newPointsGroup, addPointsIndexs, cloudArry, gTransArry)
  }
  
  // 更新当前显示索引
  currentShowIndex = machinedIntersectingIndex
}

/**
 * 重置状态（用于切换地图时）
 */
export function resetIntersectPointsState() {
  currentShowIndex = []
}

