import Base from './base';
import { getActualPoint, getClickPoint, createSvg, keepLastIndex, getInitialPoint, getHtmlToText, createElement, pastePlainText } from './utils';
import { onClickOutside } from '../ui_utils'

export default class Shape extends Base {
  constructor ({
    container,
    annotation = null,
    page,
    viewport,
    scale,
    eventBus,
    layer,
    show = false,
    enableReply = true
  }) {
    super({
      container,
      annotation,
      page,
      layer,
      viewport,
      scale,
      eventBus,
    })
    this.enableReply = enableReply

    this.hidden = true
    this.initial = false

    this.leftTop = null
    this.rightBottom = null

    this.newLeftTop = null
    this.newRightBottom = null

    this.startCircle = null
    this.endCircle = null

    this.show = show

    this.onContainerClick = this.handleContainerClick.bind(this)
    this.onMousedown = this.handleMouseDown.bind(this)
    this.onMousemove = this.handleMouseMove.bind(this)
    this.onMouseup = this.handleMouseUp.bind(this)
    this.onDelete = this.handleDelete.bind(this)
    this.onOpenReply = this.openReply.bind(this)
    this.onBlur = this.handleFreetextEditElementBlur.bind(this)
    this.onDbclick = this.handleElementDbClick.bind(this)
    this.handleStopPropagation = this.handleStopPropagation.bind(this)
    this.onPaste = this.handleFreetextEditElementPaste.bind(this)
    this.render()
  }

  setCss (ele, cssText) {
    if (!ele) return
    if (cssText) {
      for (let key in cssText) {
        ele.style[key] = cssText[key]
      }
    }
  }

  render () {
    const { width, height } = this.viewport
    const annotation = this.annotation

    const { leftTop, rightBottom } = this.getActualRect(
      this.viewport,
      this.viewport.scale
    )
    this.initialRect = {
      width: Math.abs(leftTop.x - rightBottom.x),
      height: Math.abs(leftTop.y - rightBottom.y)
    }

    this.leftTop = leftTop
    this.rightBottom = rightBottom

    const rect = this.calculate(this.leftTop, this.rightBottom)

    if (!annotation.color) {
      annotation.color = '#000000'
    }

    if (!annotation.bgColor) {
      annotation.bgColor = 'transparent'
    }

    if (!annotation.fontSize) {
      annotation.fontSize = 16
    }

    const annotationContainer = document.createElement('div')
    annotationContainer.className = 'annotation'
    this.setCss(annotationContainer, {
      top: rect.top - 2 + 'px',
      left: rect.left - 4 + 'px',
    })
    this.annotationContainer = annotationContainer

    let freetextEditElement = document.createElement('div')
    freetextEditElement.setAttribute('role', 'textbox')
    freetextEditElement.setAttribute('contenteditable', true)
    freetextEditElement.setAttribute('spellcheck', false)
    freetextEditElement.className = 'freetext'

    const maxWidth = width - this.leftTop.x
    const maxHeight = height - this.leftTop.y

    const textAlignment = annotation.textAlignment || 'left'

    this.setCss(freetextEditElement, {
      maxWidth: maxWidth+ 'px',
      maxHeight: maxHeight + 'px',
      fontSize: annotation.fontSize + 'px',
      color: annotation.color,
      textAlign: textAlignment,
      lineHeight: '1.2em',
      padding: '2px 4px',
      overflow: 'auto',
      backgroundColor: annotation.bgColor,
      '-webkit-user-select': 'text'
    })

    this.freetextEditElement = freetextEditElement

    let freetextElement = document.createElement('div')
    freetextElement.className = 'freetext'

    this.setCss(freetextElement, {
      width: rect.width+ 'px',
      height: rect.height + 'px',
      fontSize: '16px',
      color: annotation.color,
      textAlign: textAlignment,
      lineHeight: '1.2em',
      padding: '2px 4px',
      overflow: 'hidden',
      backgroundColor: annotation.bgColor
    })
    if (annotation.contents) {
      freetextElement.innerHTML = annotation.contents
      freetextEditElement.innerHTML = annotation.contents
    } else if (annotation['contents-richtext']) {
      const parser = new window.DOMParser();
      const xmlDoc = parser.parseFromString(annotation['contents-richtext'], 'text/xml');
      const error = xmlDoc.getElementsByTagName("parsererror")
      if (error.length > 0) {
        freetextElement.innerHTML = annotation['contents-richtext']
        freetextEditElement.innerHTML = annotation['contents-richtext']
      } else {
        freetextElement.innerHTML = xmlDoc.firstElementChild.innerText
        freetextEditElement.innerHTML = xmlDoc.firstElementChild.innerText
      }
    }

    this.freetextElement = freetextElement

    this.appendOrRemoveFreetextElement('append')

    this.container.append(this.annotationContainer)

    this.outerLineContainer = document.createElement('div')
    this.outerLineContainer.className = 'outline-container'

    this.deletetButton = createSvg(
      "svg",
      {
        width: "30",
        height: "30",
        viewBox: "0 0 30 30",
        fill: "none",
        class: 'delete-button'
      },
      {
        width: '30px',
        height: '30px'
      }
    );
    this.deletetButton.addEventListener('click', this.onDelete)
    this.deletetButton.innerHTML = this.deleteSvgStr
    this.deletetButton.style.left = (rect.left + rect.width - 30) + 'px'
    this.deletetButton.style.top = (rect.top + rect.height + 12) + 'px'

    this.replyButton = createElement(
      'div',
      {
        width: '30px',
        height: '30px',
        background: '#DDE9FF',
        borderRadius: '2px',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center'
      },
      {
        class: 'reply-button'
      }
    );
    this.replyButton.addEventListener('click', this.onOpenReply)
    this.replyButton.innerHTML = this.replySvgStr
    this.replyButton.style.left = (rect.left + rect.width - 65) + 'px'
    this.replyButton.style.top = (rect.top + rect.height + 12) + 'px'

    const outerLine = createSvg('svg', null, {
      position: 'absolute',
      zIndex: 1,
      left: `${rect.left - 12}px`,
      top: `${rect.top - 9}px`,
      width: `${rect.width + 16}px`,
      height: `${rect.height + 15}px`,
    })

    this.outerLine = outerLine

    this.moveRect = createSvg(
      "rect",
      {
        class: "move",
        'data-id': "move",
        stroke: "#1460F3",
        'stroke-width': 1,
        'fill-opacity': 0,
        width: rect.width + 10,
        height: rect.height + 9,
        x: 3,
        y: 3
      }
    );

    this.topLeftRect = createSvg(
      "rect",
      {
        class: "nw-resize",
        'data-id': "nw-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: 0,
        y: 0
      }
    );

    this.LeftRect = createSvg(
      "rect",
      {
        class: "w-resize",
        'data-id': "w-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: 0,
        y: rect.height / 2 + 4
      }
    );

    this.bottomLeftRect = createSvg(
      "rect",
      {
        class: "sw-resize",
        'data-id': "sw-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: 0,
        y: rect.height + 9
      }
    );

    this.bottomRect = createSvg(
      "rect",
      {
        class: "s-resize",
        'data-id': "s-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: rect.width / 2 + 5,
        y: rect.height + 9
      }
    );
    
    this.bottomRightRect = createSvg(
      "rect",
      {
        class: "se-resize",
        'data-id': "se-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: rect.width + 10,
        y: rect.height + 9
      }
    );

    this.rightRect = createSvg(
      "rect",
      {
        class: "e-resize",
        'data-id': "e-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: rect.width + 10,
        y: rect.height / 2 + 4
      }
    );

    this.topRightRect = createSvg(
      "rect",
      {
        class: "ne-resize",
        'data-id': "ne-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: rect.width + 10,
        y: 0
      }
    );

    this.topRect = createSvg(
      "rect",
      {
        class: "n-resize",
        'data-id': "n-resize",
        fill: "#1460F3",
        stroke: "none",
        width: 6,
        height: 6,
        x: rect.width / 2 + 5,
        y: 0
      }
    );

    this.outerLine.append(this.moveRect)
    this.outerLine.append(this.topLeftRect)
    this.outerLine.append(this.LeftRect)
    this.outerLine.append(this.bottomLeftRect)
    this.outerLine.append(this.bottomRect)
    this.outerLine.append(this.bottomRightRect)
    this.outerLine.append(this.rightRect)
    this.outerLine.append(this.topRightRect)
    this.outerLine.append(this.topRect)
    this.outerLineContainer.append(this.outerLine)
    this.outerLineContainer.append(this.deletetButton)
    this.enableReply && this.outerLineContainer.append(this.replyButton)
    this.initial = true
    if (this.show) {
      !this.layer.addMode && this.handleElementSelect()
    }
  }

  handleElementDbClick() {
    const freetextEditElement = this.freetextEditElement
    if (freetextEditElement) {
      this.outerLine.removeEventListener('mousedown', this.onMousedown)
      this.outerLine.removeEventListener('touchstart', this.onMousedown)
      this.outerLine.removeEventListener('dblclick', this.onDbclick)
      this.outerLineContainer.remove()

      this.appendOrRemoveFreetextElement('remove')

      this.appendOrRemoveFreetextEditElement('append')
    }
  }

  getFreetextRectPoint () {
    const rect = this.freetextEditElement.getBoundingClientRect()
    const { width, height } = rect
    const leftTop = this.leftTop
    this.rightBottom = {
      x: leftTop.x + width,
      y: leftTop.y + height
    }
  }

  getFreetextRect () {
    const viewport = this.viewport
    const { scale } = this.viewport
    this.getFreetextRectPoint()
    const actualLeftTopPoint = getInitialPoint(this.leftTop, viewport, scale)
    const actualRightBottomPoint = getInitialPoint(this.rightBottom, viewport, scale)
    return {
      left: actualLeftTopPoint.x,
      top: actualLeftTopPoint.y,
      right: actualRightBottomPoint.x,
      bottom: actualRightBottomPoint.y
    }
  }

  handleFreetextEditElementBlur () {
    const freetextEditElement = this.freetextEditElement
    if (freetextEditElement && freetextEditElement.innerText !== this.annotation.contents) {
      const freetextRect = this.getFreetextRect()

      const annotation = this.annotation
      const text = getHtmlToText(freetextEditElement)
      this.eventBus.dispatch('annotationChange', {
        type: 'modify',
        annotation: {
          operate: "mod-annot",
          name: annotation.name,
          pageIndex: this.page,
          pagePtr: annotation.pagePtr,
          annotPtr: annotation.annotPtr,
          contents: text,
          rect: freetextRect
        }
      })
      this.update({
        leftTop: this.leftTop,
        rightBottom: this.rightBottom
      })
      this.annotation.contents = text
      this.freetextElement.innerText = text
    }

    this.appendOrRemoveFreetextEditElement('remove')
    this.appendOrRemoveFreetextElement('append')
    this.handleContainerClick()
  }

  // 处理显示节点显示和隐藏
  appendOrRemoveFreetextElement (type) {
    const freetextElement = this.freetextElement
    if (type === 'append') {
      freetextElement.addEventListener('click', this.onContainerClick)

      this.annotationContainer.append(freetextElement)
    } else {
      freetextElement.removeEventListener('click', this.onContainerClick)

      freetextElement.remove()
    }
  }

  // 处理编辑框显示和隐藏
  appendOrRemoveFreetextEditElement (type) {
    const freetextEditElement = this.freetextEditElement
    if (type === 'append') {
      freetextEditElement.addEventListener('blur', this.onBlur)
      freetextEditElement.addEventListener('click', this.handleStopPropagation)
      freetextEditElement.addEventListener('paste', this.onPaste)
      this.annotationContainer.append(freetextEditElement)
      freetextEditElement.focus()
      keepLastIndex(freetextEditElement)
    } else {
      freetextEditElement.removeEventListener('blur', this.onBlur)
      freetextEditElement.removeEventListener('click', this.handleStopPropagation)
      freetextEditElement.removeEventListener('paste', this.onPaste)

      freetextEditElement.remove()
    }
  }

  // 处理选中
  handleElementSelect () {
    this.hidden = false
    if (this.show) {
      this.updateTool()
      this.show = false
    }
    onClickOutside([this.freetextElement, this.outerLine, this.deletetButton, this.replyButton, document.querySelector('.toggle-button')], this.handleOutside.bind(this))
  }

  // 获取实际坐标
  getActualRect (viewport, s,) {
    const annotation = this.annotation
    const { left: x1, top: y1, right: x2, bottom: y2 } = annotation.rect

    const start = getActualPoint(
      {
        x: x1,
        y: y1
      },
      viewport,
      s
    )
    const end = getActualPoint(
      {
        x: x2,
        y: y2
      },
      viewport,
      s
    )
    return {
      leftTop: {
        x: Math.min(start.x, end.x),
        y: Math.min(start.y, end.y)
      },
      rightBottom: {
        x: Math.max(start.x, end.x),
        y: Math.max(start.y, end.y)
      }
    }
  }

  rectCalc ({ leftTop, rightBottom }) {
    return {
      top: leftTop.y < rightBottom.y ? leftTop.y : rightBottom.y,
      left: leftTop.x < rightBottom.x ? leftTop.x : rightBottom.x,
      width: Math.abs(rightBottom.x - leftTop.x),
      height: Math.abs(rightBottom.y - leftTop.y),
    };
  };

  calculate (leftTop, rightBottom) {
    const initRect = this.rectCalc({ leftTop, rightBottom });

    return {
      top: initRect.top,
      left: initRect.left,
      width: initRect.width,
      height: initRect.height,
    }
  }

  getInitialPoint () {
    const left = this.leftTop.x
    const top = this.leftTop.y
    const right = this.rightBottom.x
    const bottom = this.rightBottom.y

    const { scale: s  } = this.viewport;
    let x1, y1, x2, y2;
    x1 = left / s;
    y1 = top / s; 
    x2 = right / s;
    y2 = bottom / s;
    return {
      leftTop: {
        x: x1,
        y: y1,
      },
      rightBottom: {
        x: x2,
        y: y2,
      },
    };
  }

  selectAnnotation () {
    if (this.layer.selectedElementName === this.annotation.name) return
    this.handleContainerClick()
  }

  updateTool () {
    if (!this.initial) return
    
    if (this.hidden) {
      this.outerLineContainer.remove()
      if (this.layer.selectedElementName === this.annotation.name) {
        this.layer.selectedElementName = null
      }
    } else {
      if (this.layer.selectedElementName !== this.annotation.name) {
        const annotation = this.annotation
        this.layer.selectedElementName = annotation.name

        const annotationData = {
          ...annotation
        }
        delete annotationData.annotPtr
        delete annotationData.pagePtr
        delete annotationData.operate
        delete annotationData.targetPage

        this.eventBus.dispatch('annotationSelected', annotationData)
      }
      this.container.append(this.outerLineContainer)
      this.outerLine.addEventListener('mousedown', this.onMousedown)
      this.outerLine.addEventListener('dblclick', this.onDbclick)
      this.outerLine.addEventListener('touchstart', this.onMousedown)
      const documentViewer = this.layer.documentViewer
      const scrollElement = documentViewer.getScrollViewElement()
      scrollElement.style.touchAction = 'none'
    }
  }

  handleContainerClick (event) {
    event && event.stopPropagation()
    if (!this.hidden || this.layer.annotationStore.creating || ['redaction', 'remove'].includes(this.layer.tool) || document.querySelector('.compare-document-container').contains(event?.target)) return
    this.hidden = false
    this.updateTool()
    onClickOutside([this.outerLine, this.freetextElement, this.deletetButton, this.replyButton, document.querySelector('.toggle-button')], this.handleOutside.bind(this))
  }

  handleOutside () {
    this.hidden = true

    if (this.layer.selectedElementName === this.annotation.name) {
      this.layer.selectedElementName = null
    }
    this.outerLine?.removeEventListener('mousedown', this.onMousedown)
    this.outerLine?.removeEventListener('touchstart', this.onMousedown)
    this.outerLine?.removeEventListener('dblclick', this.onDbclick)
    this.outerLineContainer?.remove()

    const documentViewer = this.layer.documentViewer
    const scrollElement = documentViewer.getScrollViewElement()
    scrollElement.style.touchAction = 'auto'
  }

  handleStopPropagation (event) {
    event.stopPropagation()
  }

  handleMouseDown (event) {
    if (event.button !== 0 && event.type === 'mousedown') return
    if (this.layer.tool) {
      event.stopPropagation()
    }
    const operatorId = event.target.getAttribute('data-id')

    const documentViewer = this.layer.documentViewer
    const scrollElement = documentViewer.getScrollViewElement()
    this.scrollTop = scrollElement.scrollTop
    this.scrollLeft = scrollElement.scrollLeft

    const { pageX, pageY } = getClickPoint(event)
    this.startState = {
      operator: operatorId,
      clickX: pageX,
      clickY: pageY,
    }

    document.addEventListener('mousemove', this.onMousemove)
    document.addEventListener('mouseup', this.onMouseup)
    document.addEventListener('touchmove', this.onMousemove)
    document.addEventListener('touchend', this.onMouseup)
  };

  handleMouseMove (event) {
    if (event.button !== 0 && event.type === 'mousemove') return
    if (event.type === 'touchmove') {
      document.querySelector('.document-container').addEventListener('scroll', event => event.preventDefault())
    }
    this.moving = true
    let { pageX, pageY } = getClickPoint(event)

    const documentViewer = this.layer.documentViewer
    const scrollElement = documentViewer.getScrollViewElement()
    const scrollTop = scrollElement.scrollTop
    const scrollLeft = scrollElement.scrollLeft
    pageX = pageX + scrollLeft - this.scrollLeft
    pageY = pageY + scrollTop - this.scrollTop

    const leftTop = this.leftTop
    const rightBottom = this.rightBottom
    const startState = this.startState

    const { width, height } = this.viewport

    const rect = {
      width: 10,
      height: 10
    }
    if (startState.operator === 'nw-resize') {
      let left = pageX - (startState.clickX - leftTop.x);
      let top = pageY - (startState.clickY - leftTop.y);
      left = Math.min(rightBottom.x - rect.width, left)
      left = Math.max(12, left)
      top = Math.min(rightBottom.y - rect.height, top)
      top = Math.max(9, top)

      this.update({
        leftTop: { x: left, y: top },
        rightBottom,
      });
    } else if (startState.operator === 'w-resize') {
      let left = pageX - (startState.clickX - leftTop.x);
      left = Math.min(rightBottom.x - rect.width, left)
      left = Math.max(12, left)

      this.update({
        leftTop: { x: left, y: leftTop.y },
        rightBottom,
      });
    } else if (startState.operator === 'sw-resize') {
      let left = pageX - (startState.clickX - leftTop.x);
      let bottom = pageY - (startState.clickY - rightBottom.y);
      left = Math.min(rightBottom.x - rect.width, left)
      left = Math.max(12, left)
      bottom = Math.min(height - 6, bottom)
      bottom = Math.max(leftTop.y + rect.height, bottom)

      this.update({
        leftTop: { x: left, y: leftTop.y },
        rightBottom: { x: rightBottom.x, y: bottom },
      });
    } else if (startState.operator === 's-resize') {
      let bottom = pageY - (startState.clickY - rightBottom.y);
      bottom = Math.min(height - 6, bottom)
      bottom = Math.max(leftTop.y + rect.height, bottom)
      this.update({
        leftTop,
        rightBottom: { x: rightBottom.x, y: bottom },
      });
    } else if (startState.operator === 'se-resize') {
      let right = pageX - (startState.clickX - rightBottom.x);
      let bottom = pageY - (startState.clickY - rightBottom.y);
      right = Math.min(width - 4, right)
      right = Math.max(leftTop.x + rect.width, right)
      bottom = Math.min(height - 6, bottom)
      bottom = Math.max(leftTop.y + rect.height, bottom)
      this.update({
        leftTop,
        rightBottom: { x: right, y: bottom },
      });
    } else if (startState.operator === 'e-resize') {
      let right = pageX - (startState.clickX - rightBottom.x);
      right = Math.min(width - 4, right)
      right = Math.max(leftTop.x + rect.width, right)
      this.update({
        leftTop,
        rightBottom: { x: right, y: rightBottom.y },
      });
    } else if (startState.operator === 'ne-resize') {
      let right = pageX - (startState.clickX - rightBottom.x);
      let top = pageY - (startState.clickY - leftTop.y);
      right = Math.min(width - 4, right)
      right = Math.max(leftTop.x + rect.width, right)
      top = Math.min(rightBottom.y - rect.height, top)
      top = Math.max(9, top)
      this.update({
        leftTop: { x: leftTop.x, y: top },
        rightBottom: { x: right, y: rightBottom.y },
      });
    } else if (startState.operator === 'n-resize') {
      let top = pageY - (startState.clickY - leftTop.y);
      top = Math.min(rightBottom.y - rect.height, top)
      top = Math.max(9, top)
      this.update({
        leftTop: { x: leftTop.x, y: top },
        rightBottom,
      });
    } else if (startState.operator === 'move') {
      let left, top, right, bottom
      const documentViewer = this.layer.documentViewer
      let windowCoordinates = this.getMouseLocation(event);
      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
      if (page.first && page.first !== (this.page + 1)) {
        const pagePoint = documentViewer.windowToPage(windowCoordinates, page.first, false)

        const annotationHeight = Math.abs(leftTop.y - rightBottom.y)
        left = pageX - (startState.clickX - leftTop.x)
        top = page.first > (this.page + 1) ? pagePoint.y : pagePoint.y - annotationHeight
        right = pageX - (startState.clickX - rightBottom.x)
        bottom = page.first > (this.page + 1) ? pagePoint.y + annotationHeight : pagePoint.y
        this.page = page.first - 1

        this.annotationContainer.remove()
        this.outerLineContainer.remove()
        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
        container.append(this.annotationContainer)
        container.append(this.outerLineContainer)

        this.container = container
      } else {
        left = pageX - (startState.clickX - leftTop.x);
        top = pageY - (startState.clickY - leftTop.y);
        right = pageX - (startState.clickX - rightBottom.x);
        bottom = pageY - (startState.clickY - rightBottom.y);

        const windowPoint1 = documentViewer.pageToWindow({
          x: left,
          y: top
        }, this.page + 1, false)
        const windowPoint2 = documentViewer.pageToWindow({
          x: right,
          y: bottom
        }, this.page + 1, false)
        let x = 0, y = 0
        if (pageY > startState.clickY) {
          y = scrollElement.offsetHeight - (windowPoint2.y - scrollElement.scrollTop - scrollElement.offsetTop)
          y = y < 100 ? 5 : 0
        } else if (pageY < startState.clickY) {
          y = windowPoint1.y - scrollElement.scrollTop - scrollElement.offsetTop
          y = y < 100 ? -5 : 0
        }
        if (pageX > startState.clickX) {
          x = scrollElement.offsetWidth - (windowPoint2.x - scrollElement.scrollLeft - scrollElement.offsetLeft)
          x = x < 100 ? 5 : 0
        } else if (pageX < startState.clickX) {
          x = (windowPoint1.x - scrollElement.scrollLeft - scrollElement.offsetLeft)
          x = x < 100 ? -5 : 0
        }

        if (x || y) {
          scrollElement.scrollTop += y
          scrollElement.scrollLeft += x
        }

        const rect = {
          width: Math.abs(left - right),
          height: Math.abs(bottom - top)
        }
        if (left < right) {
          left = Math.max(12, left)
          left = Math.min(width - rect.width - 4, left)
          right = Math.max(rect.width + 12, right)
          right = Math.min(width - 4, right)
        } else {
          right = Math.max(4, right)
          right = Math.min(width - rect.width - 12, right)
          left = Math.max(rect.width + 4, left)
          left = Math.min(width - 12, left)
        }
  
        if (bottom < top) {
          bottom = Math.max(6, bottom)
          bottom = Math.min(height - rect.height - 9, bottom)
          top = Math.max(rect.height + 6, top)
          top = Math.min(height - 9, top)
        } else {
          top = Math.max(9, top)
          top = Math.min(height - rect.height - 6, top)
          bottom = Math.max(rect.height + 9, bottom)
          bottom = Math.min(height - 6, bottom)
        }
      }

      this.update({
        leftTop: { x: left, y: top },
        rightBottom: { x: right, y: bottom },
      })
    }
    startState.clickX = pageX
    startState.clickY = pageY  
  }

  handleMouseUp (event) {
    if (event.button !== 0 && event.type === 'mouseup') return
    if (this.layer.tool) {
      event.stopPropagation()
    }
    if (event.type === 'touchend') {
      document.querySelector('.document-container').style.overflow = 'auto'
    }
    this.moving = false
    document.removeEventListener('mousemove', this.onMousemove)
    document.removeEventListener('mouseup', this.onMouseup)
    document.removeEventListener('touchmove', this.onMousemove)
    document.removeEventListener('touchend', this.onMouseup)
    this.scrollLeft = 0
    this.scrollTop = 0

    const annotation = this.annotation
    const { leftTop, rightBottom } = this.getInitialPoint()

    const rect = {
      left: leftTop.x,
      top: leftTop.y,
      right: rightBottom.x,
      bottom: rightBottom.y
    }
    if (rect === annotation.rect && annotation.pageIndex === this.page) return
    annotation.rect = rect

    if (annotation.pageIndex !== this.page) {
      const annotationData = {
        type: 'delete',
        annotation: {
          operate: "del-annot",
          name: annotation.name,
          pageIndex: annotation.pageIndex,
          annotPtr: annotation.annotPtr
        }
      }
      this.eventBus.dispatch('annotationChange', annotationData)

      const newAnnotationData = Object.assign({}, annotation)
      delete newAnnotationData.annotPtr
      delete newAnnotationData.pagePtr
      delete newAnnotationData.name
      newAnnotationData.operate = 'add-annot'
      newAnnotationData.pageIndex = this.page
      this.eventBus.dispatch('annotationChange', {
        type: 'add',
        show: true,
        annotation: newAnnotationData
      })

      this.annotationContainer.remove()
      this.outerLineContainer.remove()
    } else {
      this.eventBus.dispatch('annotationChange', {
        type: 'modify',
        annotation: {
          operate: "mod-annot",
          name: annotation.name,
          pageIndex: this.page,
          pagePtr: annotation.pagePtr,
          annotPtr: annotation.annotPtr,
          rect
        }
      })
    }
  }

  update ({ leftTop, rightBottom }) {
    const { width, height } = this.viewport
    const rect = this.calculate(leftTop, rightBottom)

    this.leftTop = leftTop
    this.rightBottom = rightBottom

    this.setCss(this.annotationContainer, {
      top: rect.top - 2 + 'px',
      left: rect.left - 4 + 'px',
    })

    const maxWidth = width - leftTop.x
    const maxHeight = height - leftTop.y
    this.setCss(this.freetextEditElement, {
      maxWidth: maxWidth+ 'px',
      maxHeight: maxHeight + 'px',
    })

    this.setCss(this.freetextElement, {
      width: rect.width+ 'px',
      height: rect.height + 'px'
    })

    this.setCss(this.outerLine, {
      left: `${rect.left - 12}px`,
      top: `${rect.top - 9}px`,
      width: `${rect.width + 16}px`,
      height: `${rect.height + 15}px`,
    })

    this.setCss(this.deletetButton, {
      left: (rect.left + rect.width - 30) + 'px',
      top: (rect.top + rect.height + 12) + 'px',
    })

    this.setCss(this.replyButton, {
      left: (rect.left + rect.width - 65) + 'px',
      top: (rect.top + rect.height + 12) + 'px',
    })
    
    
    this.moveRect.setAttribute('width',  rect.width + 10)
    this.moveRect.setAttribute('height',  rect.height + 9)
    
    this.LeftRect.setAttribute("y", rect.height / 2 + 4)

    this.bottomLeftRect.setAttribute("y", rect.height + 9)

    this.bottomRect.setAttribute("x", rect.width / 2 + 5)
    this.bottomRect.setAttribute("y", rect.height + 9)

    this.bottomRightRect.setAttribute("x", rect.width + 10)
    this.bottomRightRect.setAttribute("y", rect.height + 9)

    this.rightRect.setAttribute("x", rect.width + 10)
    this.rightRect.setAttribute("y", rect.height / 2 + 4)
    
    this.topRightRect.setAttribute("x", rect.width + 10)

    this.topRect.setAttribute("x", rect.width / 2 + 5)
  }

  handleDelete (event) {
    if (this.layer.tool && event) {
      event.stopPropagation()
    }

    this.delete()
    const annotationData = {
      type: 'delete',
      annotation: {
        operate: "del-annot",
        name: this.annotation.name,
        pageIndex: this.page,
      }
    }
    this.annotation.annotPtr && (annotationData.annotation.annotPtr = this.annotation.annotPtr)

    this.eventBus.dispatch('annotationChange', annotationData)
  }

  delete () {
    this.handleOutside()
    this.annotationContainer?.remove()
    this.annotation.isDelete = true
    this.layer.deleteAnnotationInLayer({
      name: this.annotation.name
    })
  }

  openReply () {
    this.eventBus.dispatch('openAnnotationReply', this.annotation)
  }

  handleFreetextEditElementPaste (event) {
    pastePlainText(event)
  }
}
