// 节点图片大小调整插件
import { resizeImgSizeByOriginRatio } from '../utils/index'
import btnsSvg from '../svg/btns'

class NodeImgAdjust {
  //  构造函数
  constructor({ mindMap }) {
    this.mindMap = mindMap
    this.resizeBtnSize = 26 // 调整按钮的大小
    this.handleEl = null // 自定义元素，用来渲染临时图片、调整按钮
    this.isShowHandleEl = false // 自定义元素是否在显示中
    this.node = null // 当前节点实例
    this.img = null // 当前节点的图片节点
    this.rect = null // 当前图片节点的尺寸信息
    this.isMousedown = false // 当前是否是按住调整按钮状态
    this.currentImgWidth = 0 // 当前拖拽实时图片的大小
    this.currentImgHeight = 0
    this.isAdjusted = false // 是否是拖拽结束后的渲染期间
    this.bindEvent()
  }

  // 监听事件
  bindEvent() {
    this.onNodeImgMouseleave = this.onNodeImgMouseleave.bind(this)
    this.onNodeImgMousemove = this.onNodeImgMousemove.bind(this)
    this.onMousemove = this.onMousemove.bind(this)
    this.onMouseup = this.onMouseup.bind(this)
    this.onRenderEnd = this.onRenderEnd.bind(this)
    this.mindMap.on('node_img_mouseleave', this.onNodeImgMouseleave)
    this.mindMap.on('node_img_mousemove', this.onNodeImgMousemove)
    this.mindMap.on('mousemove', this.onMousemove)
    this.mindMap.on('mouseup', this.onMouseup)
    this.mindMap.on('node_mouseup', this.onMouseup)
    this.mindMap.on('node_tree_render_end', this.onRenderEnd)
  }

  // 解绑事件
  unBindEvent() {
    this.mindMap.off('node_img_mouseleave', this.onNodeImgMouseleave)
    this.mindMap.off('node_img_mousemove', this.onNodeImgMousemove)
    this.mindMap.off('mousemove', this.onMousemove)
    this.mindMap.off('mouseup', this.onMouseup)
    this.mindMap.off('node_mouseup', this.onMouseup)
    this.mindMap.off('node_tree_render_end', this.onRenderEnd)
  }

  // 节点图片鼠标移动事件
  onNodeImgMousemove(node, img) {
    // 如果当前正在拖动调整中那么直接返回
    if (this.isMousedown || this.isAdjusted || this.mindMap.opt.readonly) return
    // 如果在当前节点内移动，以及自定义元素已经是显示状态，那么直接返回
    if (this.node === node && this.isShowHandleEl) return
    // 更新当前节点信息
    this.node = node
    this.img = img
    this.rect = this.img.rbox()
    // 显示自定义元素
    this.showHandleEl()
  }

  // 节点图片鼠标移出事件
  onNodeImgMouseleave() {
    if (this.isMousedown) return
    this.hideHandleEl()
  }

  // 隐藏节点实际的图片
  hideNodeImage() {
    if (!this.img) return
    this.img.hide()
  }

  // 显示节点实际的图片
  showNodeImage() {
    if (!this.img) return
    this.img.show()
  }

  // 显示自定义元素
  showHandleEl() {
    if (!this.handleEl) {
      this.createResizeBtnEl()
    }
    this.setHandleElRect()
    document.body.appendChild(this.handleEl)
    this.isShowHandleEl = true
  }

  // 隐藏自定义元素
  hideHandleEl() {
    if (!this.isShowHandleEl) return
    this.isShowHandleEl = false
    document.body.removeChild(this.handleEl)
    this.handleEl.style.backgroundImage = ``
    this.handleEl.style.width = 0
    this.handleEl.style.height = 0
    this.handleEl.style.left = 0
    this.handleEl.style.top = 0
  }

  // 设置自定义元素尺寸位置信息
  setHandleElRect() {
    let { width, height, x, y } = this.rect
    this.handleEl.style.left = `${x}px`
    this.handleEl.style.top = `${y}px`
    this.currentImgWidth = width
    this.currentImgHeight = height
    this.updateHandleElSize()
  }

  // 更新自定义元素宽高
  updateHandleElSize() {
    this.handleEl.style.width = `${this.currentImgWidth}px`
    this.handleEl.style.height = `${this.currentImgHeight}px`
  }

  // 创建调整按钮元素
  createResizeBtnEl() {
    // 容器元素
    this.handleEl = document.createElement('div')
    this.handleEl.style.cssText = `
      pointer-events: none;
      position: fixed;
      background-size: cover;
    `
    // 调整按钮元素
    const btnEl = document.createElement('div')
    btnEl.innerHTML = btnsSvg.imgAdjust
    btnEl.style.cssText = `
      position: absolute;
      right: 0;
      bottom: 0;
      pointer-events: auto;
      background-color: rgba(0, 0, 0, 0.3);
      width: ${this.resizeBtnSize}px;
      height: ${this.resizeBtnSize}px;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: nwse-resize;
    `
    this.handleEl.appendChild(btnEl)
    // 给按钮元素绑定事件
    btnEl.addEventListener('mouseenter', () => {
      // 移入按钮，会触发节点图片的移出事件，所以需要再次显示按钮
      this.showHandleEl()
    })
    btnEl.addEventListener('mouseleave', () => {
      // 移除按钮，需要隐藏按钮
      if (this.isMousedown) return
      this.hideHandleEl()
    })
    btnEl.addEventListener('mousedown', e => {
      this.onMousedown(e)
    })
  }

  // 鼠标按钮按下事件
  onMousedown() {
    this.isMousedown = true
    // 隐藏节点实际图片
    this.hideNodeImage()
    // 将节点图片渲染到自定义元素上
    this.handleEl.style.backgroundImage = `url(${this.node.nodeData.data.image})`
  }

  // 鼠标移动
  onMousemove(e) {
    if (!this.isMousedown) return
    e.preventDefault()
    // 计算当前拖拽位置对应的图片的实时大小
    let { width: imageOriginWidth, height: imageOriginHeight } =
      this.node.nodeData.data.imageSize
    let newWidth = e.clientX - this.rect.x
    let newHeight = e.clientY - this.rect.y
    if (newWidth <= 0 || newHeight <= 0) return
    let [actWidth, actHeight] = resizeImgSizeByOriginRatio(
      imageOriginWidth,
      imageOriginHeight,
      newWidth,
      newHeight
    )
    this.currentImgWidth = actWidth
    this.currentImgHeight = actHeight
    this.updateHandleElSize()
  }

  // 鼠标松开
  onMouseup() {
    if (!this.isMousedown) return
    // 显示节点实际图片
    this.showNodeImage()
    // 隐藏自定义元素
    this.hideHandleEl()
    // 更新节点图片为新的大小
    let { image, imageTitle } = this.node.nodeData.data
    let { scaleX, scaleY } = this.mindMap.draw.transform()
    this.mindMap.execCommand('SET_NODE_IMAGE', this.node, {
      url: image,
      title: imageTitle,
      width: this.currentImgWidth / scaleX,
      height: this.currentImgHeight / scaleY,
      custom: true // 代表自定义了图片大小
    })
    this.isAdjusted = true
    this.isMousedown = false
  }

  // 渲染完成事件
  onRenderEnd() {
    if (!this.isAdjusted) {
      this.hideHandleEl()
      return
    }
    this.isAdjusted = false
  }

  // 插件被移除前做的事情
  beforePluginRemove() {
    this.unBindEvent()
  }
}

NodeImgAdjust.instanceName = 'nodeImgAdjust'

export default NodeImgAdjust
