
import { DeviceTypeEnum } from '@/enum/common'
import { useEmitter, useId } from '@/hooks'
import { Ref } from 'vue'

interface DrawData {
  id?: string,
  Points: {x: number, y: number}[],
  ctxStyle?: any,
  isLineHeight: boolean
  name: string
  hidden: boolean
  [key: string]: any
}

interface CtxProperty {
  lineWidth: number,
  fillStyle: string,
  strokeStyle: string,
  lineCap: string,
  lineJoin: string,
}

export enum DrawTypeEnum {
  'rect' = 0,
  'line' = 2
}

/**
 * 绘制热区的步骤
 * 1. 点击canvas之后，创建一个a点， 从a点到鼠标一直有一条唯一的线段，点会一直跟随鼠标
 * 2. 再次点击创建一个b点， a点与b点之间连接一条线段， 然后b点有一条线跟随鼠标移动
 * 3. 重复1 、2 步骤形成一个区域，然后双击结束绘制，同时弹出一个框，输入这个区域的名字，点击确定结束
 *
 *
 * 支持对区域的 删除 高亮
 * 绘画的drawRecords 从外部传入
 */

export class DrawController {
  el: HTMLCanvasElement
  ctx: CanvasRenderingContext2D
  isDrawing: boolean // 是否正在绘画状态
  isStarting = false // 是否开始绘画
  drawRecord: DrawData[] = [] // 绘画的全部数据
  drawType: DrawTypeEnum = DrawTypeEnum.rect // 绘制的图形有两种类型  0 是绘制区域， 2 是绘制线段
  drawEndCallback: () => void = () => {}
  ctxProperty: CtxProperty | null = null
  bgUrl = null

  private mouseupCount = 0

  constructor (
    el: Ref<HTMLCanvasElement>
  ) {
    console.log('初始化drawController')

    this.el = el.value
    this.ctx = el.value.getContext('2d')!
    this.isDrawing = false
    this.el.addEventListener('mousedown', (event: MouseEvent) => this.mousedown(event))
    this.el.addEventListener('mousemove', (event: MouseEvent) => this.mousemove(event))
    this.el.addEventListener('mouseup', (event: MouseEvent) => this.mouseup(event))
    this.el.addEventListener('dblclick', (event: MouseEvent) => this.dblclick(event))
  }

  getDrawRecordLast () {
    return this.drawRecord[this.drawRecord.length - 1]
  }

  getDrawRecord () {
    return this.drawRecord
  }

  setDrawRecord (records) {
    this.drawRecord = records
    this.clearCanvar()
    if (records.length !== 0) this.drawRectByDrawData(records)
  }

  setProperty (records: CtxProperty) {
    this.ctxProperty = records
  }

  get drawRecordsLen () {
    return this.getDrawRecord().length
  }

  start () {
    this.isStarting = true
  }

  // 取消绘制
  cacelDraw () {
    this.isStarting = false
    this.isDrawing = false
    this.mouseupCount = 0
  }

  // 传入绘制结束的回调
  drawEnd (cb : () => void) {
    this.drawEndCallback = cb
  }

  // 设置每次绘制的类型 0 是区域 2 是线段
  setDrawType (type: DrawTypeEnum) {
    this.drawType = type
  }

  // 隐藏绘制的线段
  hiddenDrawRecordsByIndex (index: number) {
    this.clearCanvar()
    this.drawRecord[index].hidden = true
    this.drawRectByDrawData()
  }

  // 这里直接传入 index即可
  showDrawRecordsByIndex (index: number) {
    this.clearCanvar()
    this.drawRecord[index].hidden = false
    this.drawRectByDrawData()
  }

  // 高亮
  showLineHieght (index: number) {
    this.clearCanvar()
    this.drawRecord[index].isLineHeight = true
    this.drawRectByDrawData()
  }

  // 取消高亮
  hiddenlLineHieght (index: number) {
    this.clearCanvar()
    this.drawRecord[index].isLineHeight = false
    this.drawRectByDrawData()
  }

  // 删除
  delLine (id: string) {
    this.clearCanvar()
    const index = this.drawRecord.findIndex(item => item.id === id)
    this.drawRecord.splice(index, 1)
    this.drawRectByDrawData()
  }

  // 缩放
  scale (scaleX, scaleY) {
    this.ctx.scale(scaleX, scaleY)
  }

  // 设置背景图片
  setBgImage (url: CanvasImageSource) {
    this.bgUrl = url as any
  }

  setDrawImage () {
    if (this.bgUrl) {
      this.ctx.drawImage(this.bgUrl as unknown as CanvasImageSource, 0, 0, this.el.width, this.el.height)
    }
  }

  // 清空画布
  clearCanvar () {
    this.ctx.clearRect(0, 0, this.el.width, this.el.height)
    this.setDrawImage()
  }

  // 设置ctx的一些绘制属性
  private setCtxProperty (records: CtxProperty) {
    for (const key in records) {
      this.ctx[key] = records[key]
    }
  }

  private mousedown (event: MouseEvent) {
    if (!this.isStarting) return
    const canvasRect = this.el.getBoundingClientRect()
    const x = event.clientX - canvasRect.left
    const y = event.clientY - canvasRect.top
    this.createDraw(x, y)

    this.isDrawing = true
  }

  private mousemove (event: MouseEvent) {
    if (!this.isDrawing) return ''
    const canvasRect = this.el.getBoundingClientRect()
    const x = event.clientX - canvasRect.left
    const y = event.clientY - canvasRect.top

    const lastRecords = this.drawRecord[this.drawRecord.length - 1]

    this.clearCanvar()

    this.drawRectByDrawData(this.drawRecord.slice(0, this.drawRecord.length - 1))
    this.setCtxProperty(this.ctxProperty!)
    this.ctx.beginPath()

    this.ctx.moveTo(lastRecords.Points[0].x, lastRecords.Points[0].y)

    lastRecords.Points.slice(1).forEach(point => {
      this.ctx.lineTo(point.x, point.y)
    })

    this.ctx.lineTo(x, y)

    this.ctx.lineTo(lastRecords.Points[0].x, lastRecords.Points[0].y)

    this.ctx.stroke()

    this.ctx.fill()
  }

  private mouseup (event: MouseEvent) {
    this.mouseupCount++
    if (this.drawType === DrawTypeEnum.line && this.mouseupCount === 2) {
      this.handleDrawed()
    }
  }

  // 双击代表本次绘画结束
  private dblclick (event: MouseEvent) {
    if (this.drawType === DrawTypeEnum.rect && this.isStarting) {
      this.handleDrawed()
    }
  }

  // 绘制结束
  private handleDrawed () {
    this.isStarting = false
    this.isDrawing = false
    this.mouseupCount = 0
    this.drawEndCallback()
  }

  // 创建每次绘制图形的基本的数据结构
  private createDraw (x: number, y: number) {
    if (this.isDrawing) {
      this.drawRecord[this.drawRecord.length - 1].Points.push({ x, y })
    } else {
      const drawItem = {
        id: useId(),
        Points: [{ x, y }],
        ctxStyle: this.ctxProperty,
        isLineHeight: false,
        name: '',
        hidden: false
      }
      this.drawRecord.push(drawItem)
    }
  }

  // 根据 传入的drawData来绘制
  drawRectByDrawData (records?: DrawData[]) {
    const _records = records || this.drawRecord
    _records.forEach(item => {
      if (item.hidden) return
      this.setCtxProperty(item.ctxStyle)
      if (item.isLineHeight) {
        this.ctx.strokeStyle = 'rgba(255, 215, 0, 1)'
        this.ctx.setLineDash([10, 10])
      } else {
        this.ctx.setLineDash([])
      }
      this.ctx.beginPath()

      this.ctx.moveTo(item.Points[0].x, item.Points[0].y) // 一个矩形的起始点
      item.Points.slice(1).forEach(point => this.ctx.lineTo(point.x, point.y)) // 绘制中间路径
      this.ctx.lineTo(item.Points[0].x, item.Points[0].y) // 最后一个点连接到起始点
      this.ctx.fill()
      // 根据绘制图形的中间的点， 与第一个y点，来确定绘制的图形的名字渲染的地方
      const pointX = item.Points.map(point => point.x).sort((a, b) => a - b)
      const pointY = item.Points.map(point => point.y).sort((a, b) => a - b)
      const midX = (pointX[0] + pointX[pointX.length - 1]) / 2
      this.ctx.font = '20px Arial'
      this.ctx.fillText(item.name, midX, pointY[0] - 20)
      this.ctx.stroke()
    })
  }
}
