import { getStroke } from "perfect-freehand";
import {
  getAbsoluteCoordinate,
  createSvg,
  getInitialPoint,
  getSvgPathFromStroke
} from '../utils';
import ArrowHelper from '../arrow'

// 绘制 Line, Square, Circle, Ink
export default class PaintShape {
  constructor({
    tool,
    color,
    svgElement,
    layer,
    container,
    viewport,
    page,
    eventBus
  }) {
    this.layer = layer
    this._tool = tool
    this.color = color
    this.svgElement = svgElement
    this.container = container
    this.viewport = viewport
    this.page = page
    this.eventBus = eventBus
    this.path = []

    this.initStartPoint = null
    this.initEndPoint = null
    this.shapeEle = null

    this.onMousedown = this.handleMouseDown.bind(this)
    this.onMouseup = this.handleMouseUp.bind(this)
    this.onMousemove = this.handleMouseMove.bind(this)

    this.init()
  }

  // Line, Square, Circle, Ink 画布初始化
  init() {
    
    this.container.removeEventListener('mousedown', this.onMousedown)
    this.container.removeEventListener('touchstart', this.onMousedown)

    this.container.addEventListener('mousedown', this.onMousedown)
    this.container.addEventListener('touchstart', this.onMousedown)

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

  // 获取当前的工具类型
  get tool() {
    return this._tool
  }

  // 设置当前的工具类型
  set tool(toolType) {
    if (toolType === this._tool) return
    if (!toolType) {
      this.reset()
    }
    this._tool = toolType
  }

  // Line, Square, Circle, Ink 画布重置
  reset() {
    this.initStartPoint = null
    this.initEndPoint = null
    this.shapeEle = null
    this.svgElement.innerHTML = ''
    this.path = []
    document.removeEventListener('mousemove', this.onMousemove)
    document.removeEventListener('mouseup', this.onMouseup)

    document.removeEventListener('touchmove', this.onMousemove)
    document.removeEventListener('touchend', this.onMouseup)

    this.container.removeEventListener('mousedown', this.onMousedown)
    this.container.removeEventListener('touchstart', this.onMousedown)
  }

  // 返回对应的 svg 元素
  checkSvgChild(tool) {
    switch (tool) {
      case 'square':
        return 'rect';
      case 'circle':
        return 'ellipse';
      case 'ink':
        return 'path';
      default:
        return 'line';
    }
  }

  // 处理鼠标按下事件
  handleMouseDown(event) {
    if (this.layer.selectedElementName) return
    const { x, y } = getAbsoluteCoordinate(this.container, event)
    this.initStartPoint = {
      x,
      y
    }

    document.addEventListener('mousemove', this.onMousemove)
    document.addEventListener('mouseup', this.onMouseup)

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

  // 处理鼠标抬起事件并添加注释
  handleMouseUp() {
    let initStartPoint = this.initStartPoint
    let initEndPoint = this.initEndPoint
    if (initEndPoint && initStartPoint.x !== initEndPoint.x && initStartPoint.y !== initEndPoint.y) {
      let start = getInitialPoint(initStartPoint, this.viewport, this.viewport.scale)
      let end = getInitialPoint(initEndPoint, this.viewport, this.viewport.scale)

      const left = Math.min(start.x, end.x)
      const top = Math.min(start.y, end.y)
      const right = Math.max(start.x, end.x)
      const bottom = Math.max(start.y, end.y)
      const rect = {
        left,
        top,
        right,
        bottom
      }
      let color = this.color
      const annotationData = {
        operate: "add-annot",
        type: this.tool === 'arrow' ? 'line' : this.tool,
        pageIndex: this.page,
        date: new Date(),
        borderWidth: 2,
        opacity: 0.8,
        borderColor: color,
        rect
      }

      this.tool === 'arrow' && (annotationData.arrow = true)

      if (annotationData.type == 'line') {
        const linePoints = [start.x, start.y, end.x, end.y]
        annotationData.linePoints = linePoints
        annotationData.rect = {
          left: left - 6,
          top: top - 6,
          right: right + 6,
          bottom: bottom + 6
        }
        if (this.tool === 'arrow') {
          annotationData.tail = 'OpenArrow'
          annotationData.arrow = true
        }
      } else if (this.tool === 'ink') {
        const { inkPointes, rect } = this.formatPath()

        annotationData.rect = rect
        annotationData.inkPointes = inkPointes
      } else {
        const linePoints = [left, bottom, right, top]
        annotationData.linePoints = linePoints
      }

      this.eventBus.dispatch('annotationChange', {
        type: 'add',
        show: true,
        annotation: annotationData
      })

    }
    // this.reset()

    this.initStartPoint = null
    this.initEndPoint = null
    this.shapeEle = null
    this.svgElement.innerHTML = ''
    this.path = []
    document.removeEventListener('mousemove', this.onMousemove)
    document.removeEventListener('mouseup', this.onMouseup)

    document.removeEventListener('touchmove', this.onMousemove)
    document.removeEventListener('touchend', this.onMouseup)
  }

  // 实时绘制注释
  handleMouseMove(event) {
    let { x, y } = getAbsoluteCoordinate(this.container, event)
    const { width, height } = this.viewport
    const scale = this.viewport.scale
    x = Math.min(width, x)
    x = Math.max(0, x)
    y = Math.min(height, y)
    y = Math.max(0, y)
    this.initEndPoint = {
      x,
      y
    }
    if (this.initStartPoint.x === this.initEndPoint.x) {
      this.initEndPoint.x = this.initEndPoint.x + 1
    }
    if (this.initStartPoint.y === this.initEndPoint.y) {
      this.initEndPoint.y = this.initEndPoint.y + 1
    }
    if (!this.shapeEle) {
      const shapeEle = createSvg(
        this.checkSvgChild(this.tool),
        {
          'fill': 'none',
          'stroke': this.color,
          'stroke-width': 2 * scale,
          'stroke-opacity': 0.8
        }
      )
      if (this.tool === 'arrow') {
        let arrowBuild = new ArrowHelper(this.initStartPoint, this.initEndPoint)
        let arrowLength = 12 * scale
        let arrowUi = arrowBuild.getEndArrow(30, arrowLength, false)
        if (arrowUi) {
          this.tail = "OpenArrow"
          arrowUi.setAttribute('tail', '')
          arrowUi.setAttribute("stroke", this.color)
          arrowUi.setAttribute("stroke-width", 2 * scale)
          arrowUi.setAttribute("fill", "none")
          arrowUi.setAttribute("stroke-opacity", 0.8)
          this.svgElement.append(arrowUi)
        }
      }
      this.shapeEle = shapeEle
      this.svgElement.append(this.shapeEle)
    } else {
      if (event.shiftKey && (this.tool === 'circle' || this.tool === 'square')) {
        const { initStartPoint, initEndPoint } = this
        const distanceX = Math.abs(initEndPoint.x - initStartPoint.x)
        const distanceY = Math.abs(initEndPoint.y - initStartPoint.y)
        const distance = Math.min(distanceX, distanceY)
        if (initStartPoint.x < initEndPoint.x) {
          initEndPoint.x = initStartPoint.x + distance
        } else {
          initEndPoint.x = initStartPoint.x - distance
        }
        if (initStartPoint.y < initEndPoint.y) {
          initEndPoint.y = initStartPoint.y + distance
        } else {
          initEndPoint.y = initStartPoint.y - distance
        }
      }
      const rect = this.calculate(this.initStartPoint, this.initEndPoint)

      const shapeEle = this.shapeEle
      if (this.tool === 'circle') {
        shapeEle.setAttribute('cx', rect.left + rect.width / 2,)
        shapeEle.setAttribute('cy', rect.top + rect.height / 2,)
        shapeEle.setAttribute('rx', (rect.width - 1) / 2,)
        shapeEle.setAttribute('ry', (rect.height - 1) / 2,)
      } else if (this.tool === 'square') {
        shapeEle.setAttribute('x', rect.left + 1 / 2,)
        shapeEle.setAttribute('y', rect.top - 1 / 2,)
        shapeEle.setAttribute('width', `${Math.abs(rect.width - 1)}px`,)
        shapeEle.setAttribute('height', `${Math.abs(rect.height - 1)}px`,)
      } else if (this.tool === 'line' || this.tool === 'arrow') {
        shapeEle.setAttribute('x1', this.initStartPoint.x);
        shapeEle.setAttribute('y1', this.initStartPoint.y);
        shapeEle.setAttribute('x2', this.initEndPoint.x);
        shapeEle.setAttribute('y2', this.initEndPoint.y);

        if (this.tool === 'arrow') {
          let tail = this.svgElement.querySelector('[tail]')
          if (tail) {
            let arrowBuild = new ArrowHelper(this.initStartPoint, this.initEndPoint)
            let arrowLength = 12 * scale
            let arrowPoints = arrowBuild.getEndArrowPoints(30, arrowLength)
            let points = ''
            arrowPoints.forEach(element => {
              if (points.length > 0) {
                points = points + ' '
              }
              points = points + `${element.x},${element.y}`
            });
            if (points.length > 0) {
              tail.setAttribute('points', points)
            }
          }
        }
      } else if (this.tool === 'ink') {
        this.path.push([x, y])
        const d = this.getFreeDrawSvgPath()
        shapeEle.setAttribute('d', d)
      }
    }
  }

  // 获取 Ink 注释的路径
  getFreeDrawSvgPath() {
    const options = {
      simulatePressure: false,
      size: 1,
      thinning: 0,
      smoothing: 0.3,
      streamline: 0.5,
      easing: (t) => Math.sin((t * Math.PI) / 2),
      last: false
    }
    return getSvgPathFromStroke(getStroke(this.path, options))
  }

  // 获取点对应的 PDF 规范原始坐标
  handlePoint(point) {
    const newPoint = getInitialPoint(
      {
        x: point[0],
        y: point[1]
      },
      this.viewport,
      this.viewport.scale
    )
    return {
      x: newPoint.x,
      y: newPoint.y
    }
  }

  // 获取 Ink 类型的 rect 坐标
  getRect() {
    const xArray = [];
    const yArray = [];
    this.path.forEach((point) => {
      xArray.push(point[0]);
      yArray.push(point[1]);
    });
    const top = Math.min(...yArray);
    const left = Math.min(...xArray);
    const bottom = Math.max(...yArray);
    const right = Math.max(...xArray);
    this.path = this.path.map((ele) => {
      let x = ele[0] - left
      let y = ele[1] - top
      return [x, y]
    })
    return {
      left,
      top,
      bottom,
      right,
      width: right - left,
      height: bottom - top
    }
  }

  // 格式化 Ink 的坐标给 cmd 用
  formatPath() {
    let path = []
    const length = this.path.length

    const xArray = [];
    const yArray = [];
    const inkPointes = []
    for (let i = 0; i < length; i++) {
      const point = this.handlePoint(this.path[i])

      xArray.push(point.x);
      yArray.push(point.y);

      path.push({
        PointX: point.x.toFixed(2),
        PointY: point.y.toFixed(2)
      })
    }
    inkPointes.push(path)

    const left = Math.min(...xArray);
    const bottom = Math.max(...yArray);
    const right = Math.max(...xArray);
    const top = Math.min(...yArray);

    return {
      inkPointes,
      rect: {
        left,
        bottom,
        right,
        top
      }
    }
  }

  // 获取注释的 rect 坐标
  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),
    };
  };

  // 获取注释的 rect 坐标
  calculate(start, end) {
    const initRect = this.rectCalc({ start, end });
    const actualbdwidth = 1 * this.viewport.scale

    return {
      top: initRect.top - actualbdwidth,
      left: initRect.left - actualbdwidth,
      width: initRect.width + actualbdwidth * 2,
      height: initRect.height + actualbdwidth * 2,
    }
  }

}
