<template>
  <canvas
    :style="{ backgroundColor: backgroundColor, borderRadius: borderRadius }"
    ref="inkCanvasRef"
    :width="width"
    :height="height"
    id="ink-canvas"
  ></canvas>
  <div></div>
</template>

<script lang="ts" setup>
import { reactive, computed, onMounted, onBeforeUnmount, watch, ref } from 'vue'
import { getHandWriting } from '@/http/api'

type WriteType = 'CN' | 'EN'

type State = {
  handWrite: string
  isClick: boolean
  //轨迹X
  clickX: number[]
  //轨迹Y
  clickY: number[]
  //轨迹标志位，为1则是终点
  clickC: number[]
  X: number
  Y: number
  oldX: number
  oldY: number
  timer: number
  list: string[] //返回汉字列表
}

type Props = {
  width: number
  height: number
  lang: WriteType
  backgroundColor: string
  borderRadius: string
  fillText: string
  fillFontSize: string
  strokeStyle: string
  fillStyle: string
}

const props = withDefaults(defineProps<Props>(), {
  width: 800,
  height: 800,
  lang: 'CN',
  backgroundColor: '#f2f2f2',
  borderRadius: '10px',
  fillText: '手写区域',
  fillFontSize: '100px',
  strokeStyle: '#000',
  fillStyle: 'rgba(85, 73, 54, 0.1)'
})
const emits = defineEmits(['result'])

const state = reactive<State>({
  handWrite: '',
  isClick: false,
  //轨迹X
  clickX: [],
  //轨迹Y
  clickY: [],
  //轨迹标志位，为1则是终点
  clickC: [],
  X: 0,
  Y: 0,
  oldX: 0,
  oldY: 0,
  timer: 0,
  list: [] //返回汉字列表
})

const inkCanvasRef = ref<HTMLCanvasElement | null>(null)
const ctxComRef = computed(() => (inkCanvasRef.value as HTMLCanvasElement).getContext('2d'))

function updateBound() {
  const bound = (inkCanvasRef.value as HTMLCanvasElement).getBoundingClientRect()
  state.X = bound.x
  state.Y = bound.y
}
function down(ev: MouseEvent | TouchEvent) {
  const cx = Math.floor((ev as MouseEvent).clientX || (ev as TouchEvent).targetTouches[0].clientX) - state.X

  const cy = Math.floor((ev as MouseEvent).clientY || (ev as TouchEvent).targetTouches[0].clientY) - state.Y

  clearTimeout(state.timer)
  state.oldX = cx
  state.oldY = cy
  ctxComRef.value && ctxComRef.value.beginPath()
  state.isClick = true
}
function move(ev: MouseEvent | TouchEvent) {
  ev.preventDefault()
  if (state.isClick) {
    const cx = Math.floor((ev as MouseEvent).clientX || (ev as TouchEvent).targetTouches[0].clientX) - state.X
    const cy = Math.floor((ev as MouseEvent).clientY || (ev as TouchEvent).targetTouches[0].clientY) - state.Y

    state.clickX.push(cx)
    state.clickY.push(cy)
    state.clickC.push(0)

    //画图
    ;(ctxComRef.value as CanvasRenderingContext2D).lineWidth = 8
    ;(ctxComRef.value as CanvasRenderingContext2D).lineCap = 'round'
    ctxComRef.value && ctxComRef.value.moveTo(state.oldX, state.oldY)
    ctxComRef.value && ctxComRef.value.lineTo(cx, cy)
    ctxComRef.value && ctxComRef.value.stroke()
    state.oldX = cx
    state.oldY = cy
  }
}
function mouseUp() {
  if (state.isClick) {
    state.isClick = false
    state.timer = setTimeout(() => {
      reload()
    }, 1500)
    //标记最后一点为终点
    state.clickC.pop()
    state.clickC.push(1)
    _getHandWriting()
  }
}

function reload() {
  if (!inkCanvasRef.value) {
    return
  }
  state.clickX = []
  state.clickY = []
  state.clickC = []
  ;(ctxComRef.value as CanvasRenderingContext2D).strokeStyle = props.strokeStyle
  ;(ctxComRef.value as CanvasRenderingContext2D).fillStyle = props.fillStyle
  ;(ctxComRef.value as CanvasRenderingContext2D).clearRect(0, 0, props.width, props.height)
  ;(ctxComRef.value as CanvasRenderingContext2D).font = `bold ${props.fillFontSize} Arial`
  ;(ctxComRef.value as CanvasRenderingContext2D).textAlign = 'center'
  ;(ctxComRef.value as CanvasRenderingContext2D).textBaseline = 'middle'
  ctxComRef.value && ctxComRef.value.fillText(props.fillText, props.width / 2, props.height / 2, 1000)
}
function _getHandWriting() {
  const params = {
    lib: props.lang,
    lpXis: state.clickX,
    lpYis: state.clickY,
    lpCis: state.clickC
  }
  getHandWriting(params)
    .then(res => {
      const { data } = res
      state.list = data as string[]
    })
    .catch(err => {
      console.log(err)
    })
}

watch(
  () => state.list,
  newVal => {
    emits('result', newVal)
  }
)

onMounted(() => {
  updateBound()
  reload()
  ;(inkCanvasRef.value as HTMLElement).addEventListener('touchstart', down)
  ;(inkCanvasRef.value as HTMLElement).addEventListener('touchmove', move)
  ;(inkCanvasRef.value as HTMLElement).addEventListener('touchend', mouseUp)
})
onBeforeUnmount(() => {
  ;(inkCanvasRef.value as HTMLElement).removeEventListener('touchstart', down)
  ;(inkCanvasRef.value as HTMLElement).removeEventListener('touchmove', move)
  ;(inkCanvasRef.value as HTMLElement).removeEventListener('touchend', mouseUp)
})

defineExpose({
  updateBound,
  reload
})

defineExpose({
  updateBound,
  reload
})
</script>
