import IconTranslateXZ from '@/assets/icons/translate_xz.png'
import IconTranslateY from '@/assets/icons/translate_y.png'
import IconRotate from '@/assets/icons/rotate.png'

class EventEmitter {
  constructor() {
    this.events = {}
  }
  on(name, callback) {
    if (!this.events[name]) {
      this.events[name] = []
    }
    this.events[name].push(callback)
  }
  emit(name, data) {
    this.events[name].forEach((callback) => {
      callback.call(this, data)
    })
  }
}

class DragControl extends EventEmitter {
  constructor(object, _vueComponent) {
    super()

    if (object.pickable !== false) {
      object.pickable = false // 修复拖拽物体忽大忽小问题，注：鼠标释放时还需要恢复为 true，否则无法选中
    }
    object.addComponent(
      new THING.EXTEND.DragControlComponent(),
      'dragControlComponent'
    )

    this.btnDataMap = {}
    this.btnMap = {}
    this.downBtnID = null
    this.offset = null
    this.btnOffset = [32, 0]
    this.transformCtrl = object.dragControlComponent
    this.object = object

    this._addControl(object)
  }

  _btnDown(e) {
    const downBtnID = e.srcElement.id
    this.downBtnID = downBtnID
    this._hideOtherBtn(downBtnID)

    this.emit('btndown')

    e.preventDefault()

    if (!this.offset) {
      let topLength = document.getElementById(downBtnID).style.top.length
      let leftLength = document.getElementById(downBtnID).style.left.length

      let top = document
        .getElementById(downBtnID)
        .style.top.slice(0, topLength - 2)
      let left = document
        .getElementById(downBtnID)
        .style.left.slice(0, leftLength - 2)

      this.offset = [e.x - left, e.y - top]
    }

    this._addEvent()
  }

  _showAllBtn() {
    document.querySelectorAll('.btn-operate').forEach((item) => {
      item.style.opacity = 1
    })
  }

  _addEvent() {
    document.onmousemove = (e) => {
      if (this.downBtnID && this.transformCtrl) {
        let data = JSON.parse(JSON.stringify(this.btnDataMap[this.downBtnID]))
        data.x = e.x
        data.y = e.y
        data.shift = e.shiftKey
        data.step = 0.01
        data.btnOffset = this.btnOffset
        data.offset = this.offset
        this.transformCtrl.update(data)

        this.emit('btnmove', {
          downBtnId: this.downBtnID,
        })
      }
    }

    document.onmouseup = () => {
      if (this.downBtnID && this.transformCtrl) {
        this.emit('btnup')

        // 记录 btn 的位置
        this.downBtnID = undefined
        this.transformCtrl.stop()
        this._showAllBtn()
      }
    }
  }

  _hideOtherBtn(id) {
    document.querySelectorAll('.btn-operate').forEach((item) => {
      if (item.id !== id) {
        item.style.opacity = 0
      }
    })
  }

  _createBtn(id, width, height, bgImg) {
    var div = document.createElement('div')
    div.id = id
    div.className = 'btn-operate'
    div.style.width = width + 'px'
    div.style.height = height + 'px'
    div.style.background = `url(${bgImg}) no-repeat center / contain`
    div.style.position = 'absolute'
    div.style.zIndex = 999
    div.style.transform = 'translateX(-16px)'
    document.querySelector('#app').appendChild(div)
    return div
  }

  _addControl() {
    this.object.on(
      'TRANSFORM_CONTROL_UPDATE',
      (ev) => {
        const data = ev.data
        for (let element of data) {
          const mode = element.mode
          const axis = element.axis
          const anchor = element.anchor
          let id = mode + '_' + axis
          if (mode === 'scale') {
            id = id + '_' + anchor.join('_')
          }
          const btn = this.btnMap[id]

          if (btn) {
            this.btnDataMap[id] = element
            this._setBtnPos(btn, element, mode, axis)
          } else {
            let bgImg = this._getBtnImg(mode, axis)
            if (!bgImg) {
              continue
            }

            const div = this._createBtn(id, 30, 30, bgImg)
            this.btnMap[id] = div
            div.addEventListener('mousedown', this._btnDown.bind(this))
            div.addEventListener('click', (e) => e.stopPropagation()) // 如果是按钮，阻止 clickOutside
          }
        }
      },
      'OBJ_DRAG_EVENT_TAG_0'
    )
  }

  _getBtnImg(mode, axis) {
    let bgImg = null
    if (mode == 'translate') {
      if (axis === 'y') {
        bgImg = IconTranslateY
      }
      if (axis === 'xz') {
        bgImg = IconTranslateXZ
      }
    }
    if (mode == 'angle') {
      bgImg = IconRotate
    }
    return bgImg
  }

  _setBtnPos(btn, element, mode, axis) {
    if (!element.pos) {
      return
    }

    if (mode == 'translate' && axis == 'y') {
      btn.style.left = element.pos[0] - this.btnOffset[0] + 'px'
    } else if (mode == 'angle' && axis == 'y') {
      btn.style.left = element.pos[0] + this.btnOffset[0] + 'px'
    } else {
      btn.style.left = element.pos[0] + 'px'
    }
    btn.style.top = element.pos[1] + 'px'
  }

  destroy() {
    document.onmousemove = document.onmouseup = null
    if (!this.object || this.object.destroyed) return

    this.object.pickable = true
    this.object.removeComponent('dragControlComponent')
    this.object.off(
      'TRANSFORM_CONTROL_UPDATE',
      undefined,
      'OBJ_DRAG_EVENT_TAG_0'
    )

  }
}

export default DragControl
