/**
 * 3D 对象创建工具类
 * 从 robot_map_editor 移植，用于创建各种 3D 网格对象
 */

import * as THREE from 'three'

// 注意：Line2, LineMaterial, LineGeometry 需要从 three 的 examples 导入
// 如果项目中已经有这些文件，可以直接引用
// 否则需要从 three/examples/jsm/lines/ 复制或通过 CDN 引入

// 临时注释，待后续集成
// import { Line2 } from 'three/examples/jsm/lines/Line2'
// import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
// import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'

// 流标记纹理（点击地面时的波纹效果）
const flowmarkTexture = new THREE.TextureLoader().load(
  '/static_assets/img/hit_effect.png'
)

/**
 * 创建形状网格（矩形）
 * @param {Array} leftLine - 左边线坐标
 * @param {Array} rightLine - 右边线坐标  
 * @param {string} color - 颜色
 * @returns {THREE.Mesh} 网格对象
 */
const createShape = (leftLine, rightLine, color) => {
  const geometry = new THREE.BufferGeometry()
  
  const left1 = leftLine[0]
  const left2 = leftLine[1]
  const right1 = rightLine[0]
  const right2 = rightLine[1]

  const vertices = new Float32Array([
    ...left2,
    ...right2,
    ...right1,
    ...right1,
    ...left1,
    ...left2,
  ])

  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
  const material = new THREE.MeshBasicMaterial({ color: color })
  const mesh = new THREE.Mesh(geometry, material)
  return mesh
}

/**
 * 地面网格创建类
 * 用于创建和动态扩展地面平面
 */
export class CreateGroundMesh {
  constructor() {
    this.planeTop = 100
    this.planeBottom = -100
    this.planeLeft = -100
    this.planeRight = 100
    this.planeGeometry = null
    this.texture = null
    this.mesh = null
  }

  /**
   * 创建地面网格
   * @returns {THREE.Mesh} 地面网格对象
   */
  create() {
    this.planeGeometry = new THREE.BufferGeometry()
    
    const vertices1 = new Float32Array([
      this.planeLeft, this.planeBottom, 0,
      this.planeRight, this.planeBottom, 0,
      this.planeRight, this.planeTop, 0,
      this.planeRight, this.planeTop, 0,
      this.planeLeft, this.planeTop, 0,
      this.planeLeft, this.planeBottom, 0,
    ])
    
    this.planeGeometry.setAttribute(
      'position',
      new THREE.BufferAttribute(vertices1, 3)
    )
    
    const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0])
    this.planeGeometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))

    this.texture = new THREE.TextureLoader().load('/static_assets/img/ground.png')
    this.texture.wrapS = THREE.RepeatWrapping
    this.texture.wrapT = THREE.RepeatWrapping

    const width = Math.round((Math.abs(this.planeLeft) + this.planeRight) / 2)
    const height = Math.round((Math.abs(this.planeBottom) + this.planeTop) / 2)
    this.texture.repeat.set(width, height)
    
    const planeMaterial = new THREE.MeshBasicMaterial({
      map: this.texture,
      transparent: true,
      side: THREE.DoubleSide,
      depthWrite: false,
    })
    
    this.mesh = new THREE.Mesh(this.planeGeometry, planeMaterial)
    this.mesh.name = 'planeGround'
    return this.mesh
  }

  /**
   * 根据点云范围动态更新地面大小
   * @param {number} leftDistance - 左边界距离
   * @param {number} rightDistance - 右边界距离
   * @param {number} topDistance - 上边界距离
   * @param {number} bottomDistance - 下边界距离
   */
  updateGround(leftDistance, rightDistance, topDistance, bottomDistance) {
    const verticesArr = this.planeGeometry.attributes.position.array
    
    // 动态扩展地面边界（每次扩展 50 米）
    if (Math.abs(this.planeLeft) - leftDistance <= 50) {
      this.planeLeft = this.planeLeft - 50
      verticesArr[0] = this.planeLeft
      verticesArr[12] = this.planeLeft
      verticesArr[15] = this.planeLeft
    }
    
    if (this.planeRight - rightDistance <= 50) {
      this.planeRight = this.planeRight + 50
      verticesArr[3] = this.planeRight
      verticesArr[6] = this.planeRight
      verticesArr[9] = this.planeRight
    }

    if (this.planeTop - topDistance <= 50) {
      this.planeTop = this.planeTop + 50
      verticesArr[7] = this.planeTop
      verticesArr[10] = this.planeTop
      verticesArr[13] = this.planeTop
    }
    
    if (Math.abs(this.planeBottom) - bottomDistance <= 50) {
      this.planeBottom = this.planeBottom - 50
      verticesArr[1] = this.planeBottom
      verticesArr[4] = this.planeBottom
      verticesArr[16] = this.planeBottom
    }

    this.planeGeometry.setAttribute(
      'position',
      new THREE.BufferAttribute(verticesArr, 3)
    )
    this.planeGeometry.computeBoundingSphere()
    
    // 更新纹理平铺
    const width = Math.round((Math.abs(this.planeLeft) + this.planeRight) / 2)
    const height = Math.round((Math.abs(this.planeBottom) + this.planeTop) / 2)
    this.texture.repeat.set(width, height)
  }
}

/**
 * 流标记创建类（点击地面的波纹效果）
 */
export class CreateFlowmark {
  constructor() {
    this.markTimer = null
  }
  
  /**
   * 创建流标记动画
   * @param {number} distance - 距离系数
   * @param {Object} position - 位置 {x, y}
   * @returns {THREE.Mesh} 流标记网格
   */
  create(distance, position) {
    const rippleGeometry = new THREE.PlaneGeometry(1, 1)
    const rippleMaterial = new THREE.MeshBasicMaterial({
      map: flowmarkTexture,
      transparent: true,
    })

    if (this.markTimer) {
      clearTimeout(this.markTimer)
    }
    
    const currentMarkMesh = new THREE.Mesh(rippleGeometry, rippleMaterial)
    currentMarkMesh.position.set(position.x, position.y, 0)
    
    let _s = 1 * distance
    this.markTimer = setInterval(() => {
      _s += 0.25 * distance
      currentMarkMesh.scale.set(_s, _s, _s)
      // 透明度随缩放递减
      currentMarkMesh.material.opacity = 1 - (_s - distance) / (1.5 * distance)
      
      if (_s > 2.5 * distance) {
        clearTimeout(this.markTimer)
        this.markTimer = null
      }
    }, 100)
    
    return currentMarkMesh
  }
}

/**
 * 3D 边界框创建类（用于显示检测对象）
 */
export class CreateObjectBox {
  /**
   * 生成立方体边框的顶点位置
   * @param {Array} scale - [width, height, depth]
   * @returns {Array} 顶点位置数组
   */
  box(scale) {
    const width = scale[0] * 0.5
    const height = scale[1] * 0.5
    const depth = scale[2] * 0.5

    const position = []
    
    // 12 条边，每条边 2 个顶点
    position.push(
      // 底面
      -width, -height, -depth, -width, height, -depth,
      -width, height, -depth, width, height, -depth,
      width, height, -depth, width, -height, -depth,
      width, -height, -depth, -width, -height, -depth,
      
      // 顶面
      -width, -height, depth, -width, height, depth,
      -width, height, depth, width, height, depth,
      width, height, depth, width, -height, depth,
      width, -height, depth, -width, -height, depth,
      
      // 垂直边
      -width, -height, -depth, -width, -height, depth,
      -width, height, depth, -width, height, -depth,
      width, height, -depth, width, height, depth,
      width, -height, depth, width, -height, -depth
    )
    
    return position
  }
  
  /**
   * 创建3D边界框
   * @param {Object} object - 对象信息 {type, points, scale, color}
   * @returns {THREE.Group} 边界框组
   */
  create(object) {
    const group = new THREE.Group()
    const type = object.type

    if (type === 1) {
      const { points, scale, color } = object
      const geometryBoxPosition = this.box(scale[0])
      
      let lineColor = '#FF0000'
      if (color && color.length > 2) {
        lineColor = `rgba(${color[0]},${color[1]},${color[2]})`
      }
      
      // 注意：这里使用 Line2 需要额外的库支持
      // 临时使用普通 LineSegments 替代
      const lineGeometry = new THREE.BufferGeometry()
      lineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(geometryBoxPosition, 3))
      
      const lineMaterial = new THREE.LineBasicMaterial({
        color: lineColor,
        linewidth: 2,
      })
      
      const line = new THREE.LineSegments(lineGeometry, lineMaterial)
      group.add(line)
      group.position.set(points[0][0], points[0][1], points[0][2])
      
      return group
    }
  }
}

/**
 * 路径形状网格创建类（用于显示规划轨迹）
 */
export class CreateShapMesh {
  constructor() {
    this.group = new THREE.Group()
  }
  
  /**
   * 创建路径形状
   * @param {Array} points - 路径点数组
   * @param {Array} offset - 偏移量 [x, y, z]
   * @returns {THREE.Group} 路径组
   */
  create(points, offset = [0, 0, 0]) {
    this.createRoadByLine(points, 0.5, offset)
    return this.group
  }
  
  /**
   * 移除所有路径网格
   */
  remove() {
    this.group.children.forEach((itemMesh) => {
      if (itemMesh.geometry) itemMesh.geometry.dispose()
      if (itemMesh.material) itemMesh.material.dispose()
      this.group.remove(itemMesh)
    })
  }
  
  /**
   * 根据点创建路径线
   * @param {Array} points2d - 2D 点数组
   * @param {number} width - 路径宽度
   * @param {Array} offset - 偏移量
   */
  createRoadByLine(points2d, width, offset = [0, 0, 0]) {
    if (points2d.length < 2) return null
    
    let leftLine = []
    let rightLine = []

    for (let i = 1; i < points2d.length; i++) {
      const alpha = this.calcLineDirection(points2d[i - 1], points2d[i])
      if (alpha > 100) continue
      
      if (i === 1) {
        leftLine.push([
          (points2d[i - 1][0] + Math.sin(alpha) * width * 0.5) + offset[0],
          (points2d[i - 1][1] - Math.cos(alpha) * width * 0.5) + offset[1],
          (points2d[i - 1][2] ? points2d[i - 1][2] : 0) + offset[2],
        ])
        rightLine.push([
          (points2d[i - 1][0] - Math.sin(alpha) * width * 0.5) + offset[0],
          (points2d[i - 1][1] + Math.cos(alpha) * width * 0.5) + offset[1],
          (points2d[i - 1][2] ? points2d[i - 1][2] : 0) + offset[2],
        ])
      }
      
      leftLine.push([
        (points2d[i][0] + Math.sin(alpha) * width * 0.5) + offset[0],
        (points2d[i][1] - Math.cos(alpha) * width * 0.5) + offset[1],
        (points2d[i][2] ? points2d[i][2] : 0) + offset[2],
      ])
      rightLine.push([
        (points2d[i][0] - Math.sin(alpha) * width * 0.5) + offset[0],
        (points2d[i][1] + Math.cos(alpha) * width * 0.5) + offset[1],
        (points2d[i][2] ? points2d[i][2] : 0) + offset[2],
      ])

      if (leftLine.length === 2) {
        const mesh = createShape(leftLine, rightLine, '#1976d2')
        this.group.add(mesh)
        leftLine = [leftLine[1]]
        rightLine = [rightLine[1]]
      }
    }
  }
  
  /**
   * 计算两点间的方向角
   * @param {Array} startPoint - 起点 [x, y]
   * @param {Array} endPoint - 终点 [x, y]
   * @returns {number} 角度（弧度）
   */
  calcLineDirection(startPoint, endPoint) {
    if (Math.abs(endPoint[0] - startPoint[0]) < 0.0001) {
      if (Math.abs(endPoint[1] - startPoint[1]) < 0.0001) return 10000
      if (endPoint[1] < startPoint[1]) return -Math.PI / 2
      else return Math.PI / 2
    }

    if (Math.abs(endPoint[1] - startPoint[1]) < 0.0001) {
      if (endPoint[0] < startPoint[0]) return -Math.PI
      else return 0
    }

    let alpha = Math.atan((endPoint[1] - startPoint[1]) / (endPoint[0] - startPoint[0]))
    if (endPoint[0] - startPoint[0] < 0) alpha += Math.PI
    return alpha
  }
}

/**
 * 回放路径创建类（用于播放建图过程）
 */
export class CreatePlaybackeMesh {
  constructor() {
    this.group = new THREE.Group()
    this.prvPoints = []
    this.prvleftLinePoint = null
    this.prvRightLinePoint = null
    this.startGeometry = null
  }
  
  /**
   * 创建回放路径
   * @param {Array} points - 路径点
   * @returns {THREE.Group} 路径组
   */
  create(points) {
    const group = this.createRoadByLine(points, 0.5)
    return group
  }
  
  /**
   * 获取起点网格坐标
   * @param {Array} points2d - 点数组
   * @param {number} width - 宽度
   * @returns {Object} {leftLine, rightLine}
   */
  getStartMeshpoints(points2d, width = 0.5) {
    if (points2d.length < 2) return null
    
    const alpha = this.calcLineDirection(points2d[0], points2d[1])
    if (alpha < 100) {
      const leftLine = [
        [
          points2d[0][0] + Math.sin(alpha) * width * 0.5,
          points2d[0][1] - Math.cos(alpha) * width * 0.5,
          points2d[0][2] ? points2d[0][2] + 0.01 : 0.01,
        ],
        [
          points2d[1][0] + Math.sin(alpha) * width * 0.5,
          points2d[1][1] - Math.cos(alpha) * width * 0.5,
          points2d[1][2] ? points2d[1][2] + 0.01 : 0.01,
        ],
      ]
      const rightLine = [
        [
          points2d[0][0] - Math.sin(alpha) * width * 0.5,
          points2d[0][1] + Math.cos(alpha) * width * 0.5,
          points2d[0][2] ? points2d[0][2] + 0.01 : 0.01,
        ],
        [
          points2d[1][0] - Math.sin(alpha) * width * 0.5,
          points2d[1][1] + Math.cos(alpha) * width * 0.5,
          points2d[1][2] ? points2d[1][2] + 0.01 : 0.01,
        ],
      ]
      return { leftLine, rightLine }
    }
  }
  
  /**
   * 创建起点网格
   * @param {Array} points2d - 点数组
   * @returns {THREE.Mesh} 起点网格
   */
  createStartMesh(points2d) {
    const lines = this.getStartMeshpoints(points2d)
    if (lines) {
      const mesh = createShape(lines.leftLine, lines.rightLine, '#FAC850')
      this.startGeometry = mesh.geometry
      return mesh
    }
  }

  /**
   * 更新起点网格位置
   * @param {Array} points2d - 点数组
   */
  upstateStartMeshPosition(points2d) {
    const lines = this.getStartMeshpoints(points2d)
    if (this.startGeometry) {
      const left1 = lines.leftLine[0]
      const left2 = lines.leftLine[1]
      const right1 = lines.rightLine[0]
      const right2 = lines.rightLine[1]

      const vertices = new Float32Array([
        ...left2, ...right2, ...right1,
        ...right1, ...left1, ...left2,
      ])

      this.startGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
      this.startGeometry.computeBoundingSphere()
    }
  }
  
  /**
   * 创建路径线
   * @param {Array} points2d - 点数组
   * @param {number} width - 宽度
   * @returns {THREE.Group} 路径组
   */
  createRoadByLine(points2d, width) {
    const newGroup = new THREE.Group()
    if (points2d.length < 2) return null
    
    let leftLine = []
    let rightLine = []
    const alpha = this.calcLineDirection(points2d[0], points2d[1])
    
    if (alpha < 100) {
      if (this.prvleftLinePoint) {
        leftLine.push(this.prvleftLinePoint)
      } else {
        leftLine.push([
          points2d[0][0] + Math.sin(alpha) * width * 0.5,
          points2d[0][1] - Math.cos(alpha) * width * 0.5,
          points2d[0][2] ? points2d[0][2] : 0,
        ])
      }
      
      if (this.prvRightLinePoint) {
        rightLine.push(this.prvRightLinePoint)
      } else {
        rightLine.push([
          points2d[0][0] - Math.sin(alpha) * width * 0.5,
          points2d[0][1] + Math.cos(alpha) * width * 0.5,
          points2d[0][2] ? points2d[0][2] : 0,
        ])
      }
      
      leftLine.push([
        points2d[1][0] + Math.sin(alpha) * width * 0.5,
        points2d[1][1] - Math.cos(alpha) * width * 0.5,
        points2d[1][2] ? points2d[1][2] : 0,
      ])
      rightLine.push([
        points2d[1][0] - Math.sin(alpha) * width * 0.5,
        points2d[1][1] + Math.cos(alpha) * width * 0.5,
        points2d[1][2] ? points2d[1][2] : 0,
      ])

      this.prvleftLinePoint = leftLine[leftLine.length - 1]
      this.prvRightLinePoint = rightLine[rightLine.length - 1]
      
      if (leftLine.length === 2) {
        const mesh = createShape(leftLine, rightLine, '#CD853F')
        newGroup.add(mesh)
      }
    }
    return newGroup
  }
  
  /**
   * 计算线方向
   */
  calcLineDirection(startPoint, endPoint) {
    if (Math.abs(endPoint[0] - startPoint[0]) < 0.0001) {
      if (Math.abs(endPoint[1] - startPoint[1]) < 0.0001) return 10000
      if (endPoint[1] < startPoint[1]) return -Math.PI / 2
      else return Math.PI / 2
    }

    if (Math.abs(endPoint[1] - startPoint[1]) < 0.0001) {
      if (endPoint[0] < startPoint[0]) return -Math.PI
      else return 0
    }

    let alpha = Math.atan((endPoint[1] - startPoint[1]) / (endPoint[0] - startPoint[0]))
    if (endPoint[0] - startPoint[0] < 0) alpha += Math.PI
    return alpha
  }
}

