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

export default class Redaction extends Base {
  
  constructor ({
    container,
    annotation,
    page,
    viewport,
    scale,
    eventBus,
    layer,
    show = false,
    highlight
  }) {
    super({
      container,
      annotation,
      page,
      layer,
      viewport,
      scale,
      eventBus,
      show,
      highlight
    })
    this.hidden = true
    this.initial = false

    this.start = null
    this.end = null

    this.startCircle = null
    this.endCircle = null

    this.show = show
    this.highlight = highlight


    this.onMousedown = this.handleMouseDown.bind(this)
    this.onMouseup = this.handleMouseUp.bind(this)
    this.onDelete = this.handleDelete.bind(this)
    this.onKeydown = this.handleKeyDown.bind(this)
    this.render()
  }

  render () {
    const annotation = this.annotation
    if (!annotation.hasOwnProperty('rect')) return

    const { start, end } = this.getActualRect(
      this.viewport,
      this.scale
    )
    this.start = start
    this.end = end

    const wholeRect = this.calculate(start, end)

    const rects = []
    if (annotation.rects && annotation.rects.length) {
      annotation.rects.forEach(rect => {
        const { start, end } = this.getActualRect(this.viewport, this.scale, rect)
        rects.push(this.calculate(start, end))
      })
    } else {
      rects.push(wholeRect)
    }
    
    const annotationContainer = createElement(
      'div',
      {
        left: wholeRect.left + 'px',
        top: wholeRect.top + 'px',
        width: `${Math.abs(wholeRect.width)}px`,
        height: `${Math.abs(wholeRect.height)}px`,
      },
      {
        id: annotation.name,
        class: 'annotation redact'
      }
    )
    this.annotationContainer = annotationContainer

    const actualbdwidth = (annotation.borderWidth || 2) * this.scale
    const shapeElements = []
    rects.forEach(rect => {
      const shapeElement = createElement(
        'div',
        {
          left: rect.left - wholeRect.left - (annotation.erasure ? actualbdwidth / 2 : actualbdwidth) + 'px',
          top: rect.top - wholeRect.top + 'px',
          width: `${Math.abs(rect.width) + (annotation.erasure ? actualbdwidth : actualbdwidth * 2) }px`,
          height: `${Math.abs(rect.height)}px`,
          position: 'absolute',
          border: `${actualbdwidth}px solid #FF0000`,
          transition: 'none'
        }
      )
      annotation.erasure && (shapeElement.style.backgroundColor = 'rgba(255, 255, 255)')
      shapeElements.push(shapeElement)
      this.annotationContainer.append(shapeElement)
    })
    this.container.append(this.annotationContainer)
    this.annotationContainer.addEventListener('mousedown', this.handleClick.bind(this))

    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',
        zIndex: 1
      }
    );
    this.deletetButton.addEventListener('click', this.onDelete)
    this.deletetButton.innerHTML = this.deleteSvgStr

    const left = (wholeRect.left + wholeRect.width - 30) + 'px'
    const top = (wholeRect.top + wholeRect.height + 8) + 'px'
    this.deletetButton.style.left = left
    this.deletetButton.style.top = top
    
    const outerLine = document.createElementNS("http://www.w3.org/2000/svg", "svg");

    outerLine.style.position = 'absolute'
    outerLine.style.zIndex = 1
    outerLine.style.left = `${wholeRect.left - 8 - (annotation.erasure ? actualbdwidth / 2 : actualbdwidth)}px`
    outerLine.style.top = `${wholeRect.top - 8}px`
    outerLine.style.width = `${wholeRect.width + 8 * 2 + (annotation.erasure ? actualbdwidth : actualbdwidth * 2)}px`
    outerLine.style.height = `${wholeRect.height + 8 * 2}px`
    this.outerLine = outerLine

    this.moveRect = createSvg(
      "rect",
      {
        class: "move",
        'data-id': "move",
        stroke: "#4982E6",
        'stroke-width': 1,
        'fill-opacity': 0,
        width: wholeRect.width + 8 + (annotation.erasure ? actualbdwidth : actualbdwidth * 2),
        height: wholeRect.height + 8,
        x: 4,
        y: 4
      }, {
        cursor: 'pointer'
      }
    );

    this.outerLine.append(this.moveRect)
    this.outerLineContainer.append(this.outerLine)
    this.outerLineContainer.append(this.deletetButton)

    if (!annotation.erasure) {
      this.annotationContainer.addEventListener('mouseenter', () => {
        if (this.layer.pageDiv.classList.contains('selecting')) return
        shapeElements.forEach(el => {
          el.style.backgroundColor = '#000000'
          el.style.border = ''
        })
      })
      this.annotationContainer.addEventListener('mouseleave', () => {
        shapeElements.forEach(el => {
          el.style.backgroundColor = ''
          el.style.border = `${actualbdwidth}px solid #FF0000`
        })
      })

      this.moveRect.addEventListener('mouseenter', () => {
        shapeElements.forEach(el => {
          el.style.backgroundColor = '#000000'
          el.style.border = ''
        })
      })
      this.moveRect.addEventListener('mouseleave', () => {
        shapeElements.forEach(el => {
          el.style.backgroundColor = ''
          el.style.border = '2px solid #FF0000'
        })
      })
    }

    this.initial = true
  }

  getActualRect (viewport, s, rect) {
    const { left: x1, top: y1, right: x2, bottom: y2 } = rect || this.annotation.rect
    
    const start = getActualPoint(
      {
        x: x1,
        y: y1
      },
      viewport,
      s
    )
    const end = getActualPoint(
      {
        x: x2,
        y: y2
      },
      viewport,
      s
    )
    return {
      start,
      end
    }
  }

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

  calculate (start, end) {
    const initRect = this.rectCalc({ start, end });

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

  getInitialPoint () {
    const s = this.scale
    const startX = this.start.x
    const startY = this.start.y
    const endX = this.end.x
    const endY = this.end.y

    let x1, y1, x2, y2;
    x1 = startX / s;
    y1 = startY / s; 
    x2 = endX / s;
    y2 = endY / s;
    return {
      start: {
        x: x1,
        y: y1,
      },
      end: {
        x: x2,
        y: y2,
      },
    };
  }

  updateTool () {
    if (!this.initial) return
    if (this.hidden) {
      if (this.layer.annotationStore.selectedElementName === this.annotation.name) {
        this.layer.annotationStore.selectedElementName = null
      }
      this.outerLineContainer.remove()
    } else {
      if (this.layer.annotationStore.selectedElementName !== this.annotation.name) {
        const annotation = this.annotation
        this.layer.annotationStore.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('touchstart', this.onMousedown)
      document.addEventListener('keydown', this.onKeydown)
    }
  }

  handleClick () {
    if (!this.hidden || document.fullscreenElement || this.layer.annotationStore.creating || this.layer.toolMode === 'editor') return
    if (this.layer.toolMode === 'security') {
      this.hidden = false
      this.updateTool()

      onClickOutside([this.annotationContainer, this.outerLine, this.deletetButton], this.handleOutside.bind(this))
    }
  }

  handleOutside () {
    if (!this.hidden && this.layer.annotationStore.selectedElementName === this.annotation.name) {
      this.layer.annotationStore.selectedElementName = null
    }

    this.hidden = true

    if (this.layer.annotationStore.selectedElementName === this.annotation.name) {
      this.layer.annotationStore.selectedElementName = null
    }
    this.outerLine?.removeEventListener('mousedown', this.onMousedown)
    this.outerLine?.removeEventListener('touchstart', this.onMousedown)
    this.outerLineContainer?.remove()
    document.removeEventListener('keydown', this.onKeydown)
  }

  handleMouseDown (event) {
    if (event.button !== 0 && event.type === 'mousedown') return
    if (this.layer.tool) {
      event.stopPropagation()
    }
    const operatorId = event.target.getAttribute('data-id')
  
    const { pageX, pageY } = getClickPoint(event)
    this.startState = {
      operator: operatorId,
      clickX: pageX,
      clickY: pageY,
    }

    document.addEventListener('mouseup', this.onMouseup)
    document.addEventListener('touchend', this.onMouseup)

    this.handleClick()
  };

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

    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
    })
  }

  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'
    }
    document.removeEventListener('mouseup', this.onMouseup)
    document.removeEventListener('touchend', this.onMouseup)
    
    const { pageX, pageY } = getClickPoint(event)
    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return

    const annotation = this.annotation
    const { start, end } = this.getInitialPoint()

    const rect = {
      left: start.x,
      top: start.y,
      right: end.x,
      bottom: end.y
    }

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

  handleKeyDown (event) {
    const keyCode = event.keyCode || event.which
    if (keyCode === 8 || keyCode === 46) { // 8 delete键，46 backspace键
      this.handleDelete(event)
    }
  }
}
