<template>
  <div class="scaleplate">
    <!-- 显示/隐藏参考线 -->
    <div class="refer-line-img" @click="state.showReferenceLine = !state.showReferenceLine">
      <LuEye :size="16" v-if="state.showReferenceLine" />
      <LuEyeOff :size="16" v-else />
    </div>
    <!-- 标尺 -->
    <div
      class="scaleplate-horizontal"
      ref="horizontalRef"
      @mousemove="handleMouseMoveHScaleplate($event, 'horizontal')"
      @mouseenter="virtualReferLine.type = 'horizontal'"
      @mouseleave="virtualReferLine.type = null"
      @click="handleAddReferLine"
    >
      <canvas
        ref="scaleplateHorizontalRef"
        :style="{ width: horizontalWidth + 'px', height: '20px' }"
      />
    </div>
    <div
      class="scaleplate-vertical"
      ref="verticalRef"
      @mousemove="handleMouseMoveHScaleplate($event, 'vertical')"
      @mouseenter="virtualReferLine.type = 'vertical'"
      @mouseleave="virtualReferLine.type = null"
      @click="handleAddReferLine"
    >
      <canvas
        ref="scaleplateVerticalRef"
        :style="{ width: '20px', height: verticalHeight + 'px' }"
      />
    </div>

    <!-- 参考线 -->
    <div
      class="refer-line"
      v-show="state.showReferenceLine"
      v-for="item in getReferLines || []"
      :key="item.id"
      :style="{ left: item.x + 'px', top: item.y + 'px' }"
      :class="item.type === 'horizontal' ? 'refer-line-h' : 'refer-line-v'"
      @dblclick="handleRemoveReferLine(item.id)"
    >
      <UseDraggable @move="(position, event) => handleDragReferLine(position, event, item.id)">
        <span class="refer-line__txt">{{ item.value }}px</span>
        <span class="refer-line__line"></span>
      </UseDraggable>
    </div>
    <!-- 临时参考线 -->
    <div
      class="refer-line virtual-refer-line"
      :class="virtualReferLine.type === 'horizontal' ? 'refer-line-h' : 'refer-line-v'"
      :style="{
        left: virtualReferLine.x + 'px',
        top: virtualReferLine.y + 'px'
      }"
      v-show="virtualReferLine.type"
    >
      <span class="refer-line__txt">{{ virtualReferLine.value }}px</span>
      <span class="refer-line__line refer-line__dashed"></span>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { Ref } from 'vue'
import type { StageState } from './type'
import type { Page, ReferenceLine } from '@/types/page'

import { ref, watch, computed } from 'vue'
import { LuEye, LuEyeOff } from 'vue-icons-plus/lu'
import { UseDraggable } from '@vueuse/components'
import { drawScaleplate } from './utils'
import { useElementSize, useResizeObserver } from '@vueuse/core'
import { v4 } from 'uuid'

const props = defineProps<{
  state: StageState
  page?: Page
}>()

const horizontalRef = ref<HTMLElement | null>(null)
const verticalRef = ref<HTMLElement | null>(null)
const scaleplateHorizontalRef = ref<HTMLCanvasElement | null>(null)
const scaleplateVerticalRef = ref<HTMLCanvasElement | null>(null)

const { width: horizontalWidth, height: _horizontalHeight } = useElementSize(horizontalRef)
const { width: _verticalWidth, height: verticalHeight } = useElementSize(verticalRef)

// 根据滚动和缩放，重新计算辅助线位置
const getReferLines = computed(() => {
  const state = props.state
  const { scale, scrollX, scrollY, originX, originY } = props.state

  return props.page?.referenceLine
    ?.map((line) => {
      let x = line.x || 0
      let y = line.y || 0
      if (line.type === 'horizontal') {
        x = originX + line.value * scale - scrollX + 20
      } else {
        y = originY + line.value * scale - scrollY + 20
      }

      return {
        ...line,
        x,
        y
      }
    })
    .filter((line) => {
      // 过滤掉不在视口内的辅助线
      if (line.type === 'horizontal') {
        return line.x > 20 && line.x < state.viewportWidth
      } else {
        return line.y > 20 && line.y < state.viewportHeight
      }
    })
})

/* 绘制标尺刻度 */
const handleDrawHScaleplate = async () => {
  // 水平轴
  const { scale, scrollX, scrollY, originX, originY } = props.state
  drawScaleplate({
    canvas: scaleplateHorizontalRef.value!,
    canvasStyleWidth: horizontalWidth.value,
    canvasStyleHeight: 20,
    direcotion: 'horizontal',
    scale,
    scrollX,
    scrollY,
    originX,
    originY
  })
}

const handleDrawVScaleplate = async () => {
  // 水平轴
  const { scale, scrollX, scrollY, originX, originY } = props.state
  // 垂直轴
  drawScaleplate({
    canvas: scaleplateVerticalRef.value!,
    canvasStyleWidth: 20,
    canvasStyleHeight: verticalHeight.value,
    direcotion: 'vertical',
    scale,
    scrollX,
    scrollY,
    originX,
    originY
  })
}

/* =============================== 参考线 ================================= */
const virtualReferLine: Ref<ReferenceLine> = ref({
  id: '0',
  x: 0,
  y: 0,
  value: 0,
  type: null
})
/* 临时参考线位置 */
const handleMouseMoveHScaleplate = (e: MouseEvent, type: 'horizontal' | 'vertical') => {
  const { offsetX, offsetY } = e
  const { scale, originX, originY, scrollX, scrollY } = props.state

  virtualReferLine.value.x = type === 'horizontal' ? offsetX + 20 : 0
  virtualReferLine.value.y = type === 'vertical' ? offsetY + 20 : 0
  // 计算当前位置数值
  if (type === 'horizontal') {
    const offset = scrollX - originX
    virtualReferLine.value.value = Math.round((offset + offsetX) / scale)
  } else {
    const offset = scrollY - originY
    virtualReferLine.value.value = Math.round((offset + offsetY) / scale)
  }
}
/* 添加参考线 */
const handleAddReferLine = () => {
  if (!virtualReferLine.value.type) return

  props.page?.referenceLine.push({
    ...virtualReferLine.value,
    id: v4()
  })
}

/* 删除参考线 */
const handleRemoveReferLine = (id: string) => {
  props.page?.referenceLine.splice(
    props.page?.referenceLine.findIndex((item) => item.id === id),
    1
  )
}

/* 拖拽参考线 */
const handleDragReferLine = ({ x, y }: { x: number; y: number }, _: PointerEvent, id: string) => {
  const referLine = props.page?.referenceLine.find((item) => item.id === id)
  if (!referLine) return

  const { scale, originX, originY, scrollX, scrollY } = props.state
  const { left, top } = horizontalRef.value!.getBoundingClientRect()

  if (referLine.type === 'horizontal') {
    const lineX = x - left + 20
    const offsetX = scrollX - originX

    referLine.value = Math.round((lineX + offsetX - 20) / scale)
    referLine.x = lineX
  } else {
    const lineY = y - top
    const offsetY = scrollY - originY

    referLine.value = Math.round((lineY + offsetY - 20) / scale)
    referLine.y = lineY
  }
}
/* ===============================参考线结束================================= */

watch(
  () => [
    props.state.scrollX,
    props.state.scrollY,
    props.state.scale,
    props.state.viewportWidth,
    props.state.originX
  ],
  () => {
    handleDrawHScaleplate()
  },
  { immediate: false }
)

watch(
  () => [props.state.scrollY, props.state.scale, props.state.viewportHeight, props.state.originY],
  () => {
    handleDrawVScaleplate()
  },
  { immediate: false }
)

useResizeObserver(horizontalRef, handleDrawHScaleplate)
useResizeObserver(verticalRef, handleDrawVScaleplate)
</script>

<style lang="less" scoped>
.refer-line-img {
  width: 20px;
  height: 20px;
  border-bottom: solid 1px var(--border-color);
  border-right: solid 1px var(--border-color);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.scaleplate-horizontal {
  position: absolute;
  left: 20px;
  top: 0;
  width: calc(100% - 20px);
  height: 20px;
  border-bottom: solid 1px var(--border-color);
}
.scaleplate-vertical {
  position: absolute;
  top: 20px;
  left: 0;
  height: calc(100% - 20px);
  width: 20px;
  border-right: solid 1px var(--border-color);
}

.refer-line {
  position: absolute;
  font-size: 12px;
  color: blur;
  &-h {
    width: 5px;
    height: calc(100% - 16px);
    .refer-line__line {
      border-left: solid 1px red;
      cursor: e-resize;
    }
    .refer-line__dashed {
      border-left: dashed 1px red;
    }
  }
  &-v {
    width: calc(100% - 16px);
    height: 5px;
    .refer-line__line {
      border-top: solid 1px red;
      cursor: n-resize;
    }
    .refer-line__dashed {
      border-top: dashed 1px red;
    }
    .refer-line__txt {
      transform: rotate(-90deg);
      transform-origin: -4px 2px;
    }
  }
  &__line {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
  }
  &__txt {
    font-size: 12px;
    position: absolute;
    top: 0px;
    left: 4px;
    pointer-events: none;
    color: red;
  }
}
.virtual-refer-line {
  pointer-events: none;
}
</style>
