import * as THREE from 'three'

let viewCubeUpdate = null

const Viewer = function Viewer(editor) {
  const ViewerDiv = document.createElement('div')
  ViewerDiv.id = 'orientCubeWrapperDiv'
  ViewerDiv.style.position = 'absolute'
  ViewerDiv.style.left = '10px'
  ViewerDiv.style.bottom = '10px'
  ViewerDiv.style.display = 'flex'
  ViewerDiv.style.backgroundColor = 'transparent'
  ViewerDiv.style.width = '180px'
  ViewerDiv.style.height = '180px'
  ViewerDiv.style.zIndex = '999'

  const ViewerUI = document.createElement('div')
  ViewerUI.id = 'orientCubeWrapper'
  ViewerUI.style.width = '180px'
  ViewerUI.style.height = ' 180px'
  ViewerUI.style.opacity = ' 0.7'
  ViewerUI.style.transition = ' opacity 0.3s'

  ViewerDiv.appendChild(ViewerUI)
  document.body.appendChild(ViewerDiv)

  const cubeCameraDistance = 5
  const controlsViewer = editor.cameraControls
  const cubeWrapper = ViewerUI

  const cubeScene = new THREE.Scene()
  const cubeRenderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
    preserveDrawingBuffer: true
  })
  const cubeCamera = new THREE.PerspectiveCamera(50, cubeWrapper.offsetWidth / cubeWrapper.offsetHeight, 0.1, 100)
  cubeRenderer.setSize(cubeWrapper.offsetWidth, cubeWrapper.offsetHeight)
  cubeWrapper.appendChild(cubeRenderer.domElement)
  cubeScene.add(cubeCamera)
  cubeCamera.position.set(2, 2, 2)
  createArrow(new THREE.Vector3(5, 0, 0), new THREE.Vector3(-5, -5, -5), 13, 0xFF0000, 'X')// x
  createArrow(new THREE.Vector3(0, 0, 5), new THREE.Vector3(-5, -5, -5), 13, 0x0000FF, 'Z')// z
  createArrow(new THREE.Vector3(0, 5, 0), new THREE.Vector3(-5, -5, -5), 13, 0x008000, 'Y')// y
  cubeScene.add(new THREE.AmbientLight(0xffffff))
  initModel()
  let activeObject
  cubeRenderer.domElement.onmousemove = (event) => {
    const intersects = getIntersects(event)
    if (intersects.length !== 0) {
      const res = intersects.filter(function(res) {
        return res && res.object.name !== '' && res.object instanceof THREE.Mesh
      })[0]
      if (res && res.object) {
        if (activeObject) {
          if (activeObject.name === res.object.name) {
            activeObject.material.color.set('#6ad0f8')
            return
          } else {
            activeObject.material.color.set('#00c0ff')
            activeObject = null
          }
        }
        activeObject = res.object
        activeObject.material.color.set('#6ad0f8')
      }
    } else {
      if (activeObject) {
        activeObject.material.color.set('#00c0ff')
        activeObject = null
      }
    }
  }
  cubeRenderer.domElement.onclick = () => {
    if (!activeObject) return
    const _position = editor.camera.position
    const _target = editor.cameraControls.target
    const _zoom = editor.camera.zoom
    const Params = {
      positionX: Math.abs(_position.x),
      positionY: Math.abs(_position.y),
      positionZ: Math.abs(_position.z),
      positionXY: getTwoMax(_position.x, _position.y),
      positionXZ: getTwoMax(_position.x, _position.z),
      positionYZ: getTwoMax(_position.y, _position.z),
      positionXYZ: getThreeMax(_position.x, _position.y, _position.z),

      targetX: Math.abs(_target.x),
      targetY: Math.abs(_target.y),
      targetZ: Math.abs(_target.z),
      targetXY: getTwoMax(_target.x, _target.y),
      targetXZ: getTwoMax(_target.x, _target.z),
      targetYZ: getTwoMax(_target.y, _target.z),
      targetXYZ: getThreeMax(_target.x, _target.y, _target.z)
    }
    const dirAxis = {
      'TOP': [0, 0, Params.positionZ,
        0, 0, Params.targetZ,
        _zoom],
      'BOTTOM': [0, 0, -Params.positionZ,
        0, 0, -Params.targetZ,
        _zoom],
      'FRONT': [Params.positionX, 0, 0,
        Params.targetX, 0, 0,
        _zoom],
      'BACK': [-Params.positionX, 0, 0,
        -Params.targetX, 0, 0,
        _zoom],
      'LEFT': [0, -Params.positionY, 0,
        0, -Params.targetY, 0,
        _zoom],
      'RIGHT': [0, Params.positionY, 0,
        0, Params.targetY, 0,
        _zoom],

      'BACK-LEFT': [-Params.positionXY, -Params.positionXY, 0,
        -Params.targetXY, -Params.targetXY, 0,
        _zoom],
      'FRONT-LEFT': [Params.positionXY, -Params.positionXY, 0,
        Params.targetXY, -Params.targetXY, 0,
        _zoom],
      'TOP-LEFT': [0, -Params.positionYZ, Params.positionYZ,
        0, -Params.targetYZ, Params.targetYZ,
        _zoom],
      'TOP-RIGHT': [0, Params.positionYZ, Params.positionYZ,
        0, Params.targetYZ, Params.targetYZ,
        _zoom],
      'RIGHT-BOTTOM': [0, Params.positionYZ, -Params.positionYZ,
        0, Params.targetYZ, -Params.targetYZ,
        _zoom],
      'LEFT-BOTTOM': [0, -Params.positionYZ, -Params.positionYZ,
        0, -Params.targetYZ, -Params.targetYZ,
        _zoom],
      'BACK-BOTTOM': [-Params.positionXZ, 0, -Params.positionXZ,
        -Params.targetXZ, 0, -Params.targetXZ,
        _zoom],
      'TOP-FRONT': [Params.positionXZ, 0, Params.positionXZ,
        Params.targetXZ, 0, Params.targetXZ,
        _zoom],
      'FRONT-BOTTOM': [Params.positionXZ, 0, -Params.positionXZ,
        Params.targetXZ, 0, -Params.targetXZ,
        _zoom],
      'TOP-BACK': [-Params.positionXZ, 0, Params.positionXZ,
        -Params.targetXZ, 0, Params.targetXZ,
        _zoom],
      'RIGHT-FRONT': [Params.positionXY, Params.positionXY, 0,
        Params.targetXY, Params.targetXY, 0,
        _zoom],
      'BACK-RIGHT': [-Params.positionXY, Params.positionXY, 0,
        -Params.targetXY, Params.targetXY, 0,
        _zoom],

      'BACK-RIGHT-BOTTOM': [-Params.positionXYZ, Params.positionXYZ, -Params.positionXYZ,
        -Params.targetXYZ, Params.targetXYZ, -Params.targetXYZ,
        _zoom],
      'TOP-RIGHT-BACK': [-Params.positionXYZ, Params.positionXYZ, Params.positionXYZ,
        -Params.targetXYZ, Params.targetXYZ, Params.targetXYZ,
        _zoom],
      'TOP-LEFT-BACK': [-Params.positionXYZ, -Params.positionXYZ, Params.positionXYZ,
        -Params.targetXYZ, -Params.targetXYZ, Params.targetXYZ,
        _zoom],
      'TOP-LEFT-FRONT': [Params.positionXYZ, -Params.positionXYZ, Params.positionXYZ,
        Params.targetXYZ, -Params.targetXYZ, Params.targetXYZ,
        _zoom],
      'FRONT-BOTTOM-RIGHT': [Params.positionXYZ, Params.positionXYZ, -Params.positionXYZ,
        Params.targetXYZ, Params.targetXYZ, -Params.targetXYZ,
        _zoom],
      'TOP-RIGHT-FRONT': [Params.positionXYZ, Params.positionXYZ, Params.positionXYZ,
        Params.targetXYZ, Params.targetXYZ, Params.targetXYZ,
        _zoom],
      'BACK-BOTTOM-LEFT': [-Params.positionXYZ, -Params.positionXYZ, -Params.positionXYZ,
        -Params.targetXYZ, -Params.targetXYZ, -Params.targetXYZ,
        _zoom],
      'FRONT-BOTTOM-LEFT': [Params.positionXYZ, -Params.positionXYZ, -Params.positionXYZ,
        Params.targetXYZ, -Params.targetXYZ, -Params.targetXYZ,
        _zoom]
    }
    if (activeObject.name && dirAxis[activeObject.name]) {
      const position = new THREE.Vector3(dirAxis[activeObject.name][0], dirAxis[activeObject.name][1], dirAxis[activeObject.name][2])
      const target = new THREE.Vector3(dirAxis[activeObject.name][3], dirAxis[activeObject.name][4], dirAxis[activeObject.name][5])
      const zoom = dirAxis[activeObject.name][6]

      editor.cameraControls.setLookAt(position, target, zoom)
      // editor.cameraControls.setLookAt(dirAxis[activeObject.name][0],
      //   dirAxis[activeObject.name][1],
      //   dirAxis[activeObject.name][2],
      //   0, 0, 0, true)
      // editor.cameraControls.moveTo(editor.cameraControls._target.x, editor.cameraControls._target.y, editor.cameraControls._target.z, true)
      editor.camera.updateProjectionMatrix()
      editor.camera.clearViewOffset()
      updateCubeCamera()
    }

    function getTwoMax(a, b) {
      return Math.abs(a) > Math.abs(b) ? Math.abs(a) : Math.abs(b)
    }

    function getThreeMax(a, b, c) {
      return Math.abs(a) > Math.abs(b) ? Math.abs(a) > Math.abs(c) ? Math.abs(a) : Math.abs(c) : Math.abs(b) > Math.abs(c) ? Math.abs(b) : Math.abs(c)
    }
  }
  function updateCubeCamera() {
    cubeRenderer.render(cubeScene, cubeCamera)
    cubeCamera.rotation.copy(editor.camera.rotation)
    const dir = editor.camera.position.clone().sub(controlsViewer.target).normalize()
    dir.multiplyScalar(cubeCameraDistance)
    cubeCamera.position.copy(dir.multiplyScalar(cubeCameraDistance))
  }
  viewCubeUpdate = updateCubeCamera
  function createArrow(dir, origin, length = 1, color = '0xffff00', text = '') {
    // normalize the direction vector (convert to vector of length 1)
    dir.normalize()
    const arrowHelper = new THREE.ArrowHelper(dir, origin, length, color)
    cubeScene.add(arrowHelper)
  }
  function initModel() {
    const cubeMaterialRIGHT = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('RIGHT')),
      side: THREE.DoubleSide
    })
    const cubeMaterialLEFT = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('LEFT')), // BOTTOM
      side: THREE.DoubleSide
    })
    const cubeMaterialFRONT = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('FRONT')),
      side: THREE.DoubleSide
    })
    const cubeMaterialBACK = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('BACK')),
      side: THREE.DoubleSide
    })
    const cubeMaterialBOTTOM = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('BOTTOM')),
      side: THREE.DoubleSide
    })
    const cubeMaterialTOP = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('TOP')), // LEFT
      side: THREE.DoubleSide
    })
    const cubeMaterial = new THREE.MeshLambertMaterial({
      color: 0x00c0ff,
      opacity: 1,
      map: new THREE.CanvasTexture(getTextCanvas('')),
      side: THREE.DoubleSide
    })

    const SphereA = new THREE.SphereGeometry(1, 32, 32, 0, 0.5 * Math.PI, 0, 0.5 * Math.PI)
    const edgesSphereA = new THREE.EdgesGeometry(SphereA, 3)
    const CylinderB = new THREE.CylinderGeometry(1, 1, 8, 64, 1, false, 0, 0.5 * Math.PI)
    const edgesCylinderB = new THREE.EdgesGeometry(CylinderB, 3)
    const cubeC = new THREE.BoxGeometry(7.99, 4.99, 7.99)
    const CylinderD = new THREE.CylinderGeometry(1, 1, 8, 64, 1, false, 0, 0.5 * Math.PI)
    const edgesCylinderD = new THREE.EdgesGeometry(CylinderD, 3)
    const edgesMaterial = new THREE.LineBasicMaterial({
      color: '#363636'
    })

    const cube1 = new THREE.Mesh(cubeC, cubeMaterialRIGHT)
    cube1.position.y = 2.5
    cube1.rotation.y = Math.PI
    cube1.name = 'RIGHT'
    cubeScene.add(cube1)

    const cube2 = new THREE.Mesh(cubeC, cubeMaterialLEFT)// BOTTOM
    cube2.position.y = -2.5
    cube2.name = 'LEFT'
    cubeScene.add(cube2)

    const cube3 = new THREE.Mesh(cubeC, cubeMaterialFRONT)// BACK
    cube3.position.x = 2.5
    cube3.rotation.z = 0.5 * Math.PI
    cube3.name = 'FRONT'
    cubeScene.add(cube3)

    const cube4 = new THREE.Mesh(cubeC, cubeMaterialTOP)// LEFT
    cube4.position.z = 2.5
    cube4.rotation.x = 0.5 * Math.PI
    cube4.name = 'TOP'
    cubeScene.add(cube4)

    const cube5 = new THREE.Mesh(cubeC, cubeMaterialBACK)// FRONT
    cube5.position.x = -2.5
    cube5.rotation.z = 0.5 * Math.PI
    cube5.rotation.x = -Math.PI
    cube5.name = 'BACK'
    cubeScene.add(cube5)

    const cube6 = new THREE.Mesh(cubeC, cubeMaterialBOTTOM)
    cube6.position.z = -2.5
    cube6.rotation.x = -0.5 * Math.PI
    cube6.name = 'BOTTOM'
    cubeScene.add(cube6)

    const cube7 = new THREE.Mesh(CylinderB, cubeMaterial.clone())
    cube7.position.x = 4
    cube7.position.z = 4
    cube7.name = 'TOP-FRONT'
    const line7 = new THREE.LineSegments(edgesCylinderB, edgesMaterial)
    cube7.add(line7)
    cubeScene.add(cube7)

    const cube8 = new THREE.Mesh(CylinderB, cubeMaterial.clone())
    cube8.position.x = -4
    cube8.position.z = -4
    cube8.rotation.y = Math.PI
    cube8.name = 'BACK-BOTTOM'
    const line8 = new THREE.LineSegments(edgesCylinderB, edgesMaterial)
    cube8.add(line8)
    cubeScene.add(cube8)

    const cube9 = new THREE.Mesh(CylinderB, cubeMaterial.clone())
    cube9.position.x = 4
    cube9.position.z = -4
    cube9.rotation.y = 0.5 * Math.PI
    cube9.name = 'FRONT-BOTTOM'
    const line9 = new THREE.LineSegments(edgesCylinderB, edgesMaterial)
    cube9.add(line9)
    cubeScene.add(cube9)

    const cube10 = new THREE.Mesh(CylinderB, cubeMaterial.clone())
    cube10.position.x = -4
    cube10.position.z = 4
    cube10.rotation.y = -0.5 * Math.PI
    cube10.name = 'TOP-BACK'
    const line10 = new THREE.LineSegments(edgesCylinderB, edgesMaterial)
    cube10.add(line10)
    cubeScene.add(cube10)

    const cube11 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube11.position.x = 4
    cube11.position.y = 4
    cube11.rotation.z = 0.5 * Math.PI
    cube11.rotation.y = 0.5 * Math.PI
    cube11.name = 'RIGHT-FRONT'
    const line11 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube11.add(line11)
    cubeScene.add(cube11)

    const cube12 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube12.position.x = -4
    cube12.position.y = 4
    cube12.rotation.z = 0.5 * Math.PI
    cube12.rotation.y = -0.5 * Math.PI
    cube12.name = 'BACK-RIGHT'
    const line12 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube12.add(line12)
    cubeScene.add(cube12)

    const cube13 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube13.position.x = -4
    cube13.position.y = -4
    cube13.rotation.z = -0.5 * Math.PI
    cube13.rotation.y = -0.5 * Math.PI
    cube13.name = 'BACK-LEFT'
    const line13 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube13.add(line13)
    cubeScene.add(cube13)

    const cube14 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube14.position.x = 4
    cube14.position.y = -4
    cube14.rotation.z = -0.5 * Math.PI
    cube14.rotation.y = 0.5 * Math.PI
    cube14.name = 'FRONT-LEFT'
    const line14 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube14.add(line14)
    cubeScene.add(cube14)

    const cube15 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube15.position.z = 4
    cube15.position.y = 4
    cube15.rotation.x = -0.5 * Math.PI
    cube15.rotation.z = -0.5 * Math.PI
    cube15.name = 'TOP-RIGHT'
    const line15 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube15.add(line15)
    cubeScene.add(cube15)

    const cube16 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube16.position.z = -4
    cube16.position.y = 4
    cube16.rotation.x = -0.5 * Math.PI
    cube16.rotation.z = 0.5 * Math.PI
    cube16.name = 'RIGHT-BOTTOM'
    const line16 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube16.add(line16)
    cubeScene.add(cube16)

    const cube17 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube17.position.z = -4
    cube17.position.y = -4
    cube17.rotation.z = -0.5 * Math.PI
    cube17.rotation.x = 0.5 * Math.PI
    cube17.name = 'LEFT-BOTTOM'
    const line17 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube17.add(line17)
    cubeScene.add(cube17)

    const cube18 = new THREE.Mesh(CylinderD, cubeMaterial.clone())
    cube18.position.z = 4
    cube18.position.y = -4
    cube18.rotation.z = -0.5 * Math.PI
    cube18.name = 'TOP-LEFT'
    const line18 = new THREE.LineSegments(edgesCylinderD, edgesMaterial)
    cube18.add(line18)
    cubeScene.add(cube18)

    const cube19 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube19.position.x = 4
    cube19.position.y = 4
    cube19.position.z = 4
    cube19.rotation.z = -0.5 * Math.PI
    cube19.name = 'TOP-RIGHT-FRONT'
    const line19 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube19.add(line19)
    cubeScene.add(cube19)

    const cube20 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube20.position.x = 4
    cube20.position.y = 4
    cube20.position.z = -4
    cube20.rotation.z = -0.5 * Math.PI
    cube20.rotation.y = 0.5 * Math.PI
    cube20.name = 'FRONT-BOTTOM-RIGHT'
    const line20 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube20.add(line20)
    cubeScene.add(cube20)

    const cube21 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube21.position.x = -4
    cube21.position.y = 4
    cube21.position.z = -4
    cube21.rotation.y = -0.5 * Math.PI
    cube21.name = 'BACK-RIGHT-BOTTOM'
    const line21 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube21.add(line21)
    cubeScene.add(cube21)

    const cube22 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube22.position.x = -4
    cube22.position.y = 4
    cube22.position.z = 4
    cube22.name = 'TOP-RIGHT-BACK'
    const line22 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube22.add(line22)
    cubeScene.add(cube22)

    const cube23 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube23.position.x = -4
    cube23.position.y = -4
    cube23.position.z = -4
    cube23.rotation.y = -0.5 * Math.PI
    cube23.rotation.x = -0.5 * Math.PI
    cube23.name = 'BACK-BOTTOM-LEFT'
    const line23 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube23.add(line23)
    cubeScene.add(cube23)

    const cube24 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube24.position.x = 4
    cube24.position.y = -4
    cube24.position.z = -4
    cube24.rotation.y = Math.PI
    cube24.rotation.x = -0.5 * Math.PI
    cube24.name = 'FRONT-BOTTOM-LEFT'
    const line24 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube24.add(line24)
    cubeScene.add(cube24)

    const cube25 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube25.position.x = 4
    cube25.position.y = -4
    cube25.position.z = 4
    cube25.rotation.y = 0.5 * Math.PI
    cube25.rotation.x = 0.5 * Math.PI
    cube25.name = 'TOP-LEFT-FRONT'
    const line25 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube25.add(line25)
    cubeScene.add(cube25)

    const cube26 = new THREE.Mesh(SphereA, cubeMaterial.clone())
    cube26.position.x = -4
    cube26.position.y = -4
    cube26.position.z = 4
    cube26.rotation.x = 0.5 * Math.PI
    cube26.name = 'TOP-LEFT-BACK'
    const line26 = new THREE.LineSegments(edgesSphereA, edgesMaterial)
    cube26.add(line26)
    cubeScene.add(cube26)
  }
  function getTextCanvas(text) {
    const width = 64
    const height = 64
    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height
    const ctx = canvas.getContext('2d')
    ctx.fillStyle = '#8d8d8d'
    ctx.fillRect(0, 0, width, height)
    ctx.font = 'bolder 14px "Open sans", Arial'
    ctx.fillStyle = '#000000'
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillText(text, width / 2, height / 2)
    return canvas
  }
  function getIntersects(event) {
    event.preventDefault()
    // 声明 raycaster 和 mouse 变量
    const raycaster = new THREE.Raycaster()
    // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
    const x = event.offsetX
    const y = event.offsetY
    const size = cubeRenderer.getSize(new THREE.Vector2())
    const mouse = new THREE.Vector2(x / size.width * 2 - 1, -y / size.height * 2 + 1)

    raycaster.setFromCamera(mouse, cubeCamera)
    // 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
    return raycaster.intersectObjects(cubeScene.children)
  }
}

export { viewCubeUpdate, Viewer }
