<template>
  <div
    ref="boxRef"
    class="w-full h-full relative"
    @click="handleClick"
    @mousedown="handleMouseDown"
    @mousemove="handleMouseMove"
    @mouseup="handleMouseUp"
  >
    <div class="workspace flex flex-col">
      <!-- <div class="h-32px bg-bg-secondary stage-title border-b-1px border-b-solid border-border">
        <div class="px-12px leading-32px text-text-primary font-bold">{{ $t('screen') }}</div>
      </div> -->
      <div class="workspace-top">
        <!-- 画布 -->
        <DesignerCanvas
          :state="state"
          :page="page"
          :screen="screen"
          ref="canvasRef"
          @changeState="handleSetState"
        />
        <!-- 标尺 -->
        <Ruler :state="state" :page="page" v-show="state.showRuler" />
      </div>
      <!-- 底部工具栏 -->
      <div
        class="workspace-bottom flex justify-between items-center overflow-hidden bg-bg-secondary"
      >
        <div class="bottom-left flex items-center">
          <span style="margin-right: 12px">{{ $t('resolution') }}:</span>
          <span>{{ screen?.width }} * {{ screen?.height }}</span>
          <span class="ml-8px">{{ screen?.screenDirection }}</span>
          <span class="ml-8px flex items-center gap-4px theme"
            >主题:
            <el-select
              :model-value="projectStore.project?.currentTheme"
              size="small"
              style="width: 120px"
              @change="(val) => projectStore.setCurrentTheme(val)"
              :options="
                projectStore.project?.themes.map((item) => ({
                  value: item.key,
                  label: `${item.key}(${item.description})`
                }))
              "
            />
          </span>
        </div>
        <div class="bottom-right flex items-center gap-8px">
          <el-tooltip content="屏幕布局">
            <div
              v-if="projectStore.project?.meta.screenType === 'dual'"
              class="w-20px h-20px flex items-center justify-center cursor-pointer"
              @click="appStore.toggleLayout"
            >
              <LuRows2 :size="16" v-if="appStore.screenLayout === 'vertical'" />
              <LuColumns2 :size="16" v-else />
            </div>
          </el-tooltip>

          <el-tooltip content="标尺">
            <div
              class="w-20px h-20px flex items-center justify-center cursor-pointer border-1px border-solid border-transparent"
              :class="state.showRuler ? 'border-blue! border-1px border-solid bg-bg-primary' : ''"
              @click="state.showRuler = !state.showRuler"
            >
              <LuRuler :size="16" />
            </div>
          </el-tooltip>
          <el-tooltip content="控件边框">
            <div
              class="w-20px h-20px flex items-center justify-center cursor-pointer border-1px border-solid border-transparent"
              :class="state.showBorder ? 'border-blue! border-1px border-solid bg-bg-primary' : ''"
              @click="state.showBorder = !state.showBorder"
            >
              <LuBoxSelect :size="16" />
            </div>
          </el-tooltip>
          <el-tooltip content="网格">
            <div
              class="w-20px h-20px flex items-center justify-center cursor-pointer border-1px border-solid border-transparent"
              :class="state.showBgGrid ? 'border-blue! border-1px border-solid bg-bg-primary' : ''"
              @click="state.showBgGrid = !state.showBgGrid"
            >
              <LuGrid3X3 :size="16" />
            </div>
          </el-tooltip>
          <el-tooltip content="自适应缩放">
            <div
              class="w-20px h-20px flex items-center justify-center cursor-pointer"
              @click="handleCenter"
            >
              <LuFocus :size="16" />
            </div>
          </el-tooltip>

          <el-slider
            v-model="state.scale"
            :min="0.1"
            :max="4"
            :step="0.1"
            :show-tooltip="false"
            size="small"
            style="width: 140px"
          ></el-slider>
          <el-tooltip content="重置缩放">
            <span class="text-text-active inline w-30px cursor-pointer" @click="setOriginSize"
              >{{ (state.scale * 100).toFixed(0) }}%</span
            >
          </el-tooltip>
        </div>
      </div>
    </div>
    <div class="selectBox" ref="selectBoxRef"></div>
  </div>
</template>

<script setup lang="ts">
import type { StageState } from './type'
import type { Screen } from '@/types/screen'
import type { Page } from '@/types/page'

import { ref, reactive, watch, nextTick, provide } from 'vue'
import Ruler from './Ruler.vue'
import DesignerCanvas from './DesignerCanvas.vue'
import { throttle } from 'lodash-es'
import { LuGrid3X3, LuRuler, LuBoxSelect, LuRows2, LuColumns2, LuFocus } from 'vue-icons-plus/lu'
import { useProjectStore } from '@/store/modules/project'
import { useAppStore } from '@/store/modules/app'

const props = defineProps<{
  screen?: Screen
  page?: Page
}>()

const projectStore = useProjectStore()
const appStore = useAppStore()
const canvasRef = ref<InstanceType<typeof DesignerCanvas>>()
// 画布状态
const state = reactive<StageState>({
  scale: 1,
  width: 1280,
  height: 720,
  originX: 0,
  originY: 0,
  viewportWidth: 0,
  viewportHeight: 0,
  centerX: 0,
  centerY: 0,
  scrollX: 0,
  scrollY: 0,
  wrapperWidth: 0,
  wrapperHeight: 0,
  showBorder: false,
  showRuler: true,
  showBgGrid: false,
  showReferenceLine: true
})

// 监听屏幕参数变化
watch(
  () => props.screen,
  async (val) => {
    if (val) {
      state.width = val.screenDirection?.includes('竖屏') ? val.height : val.width
      state.height = val.screenDirection?.includes('竖屏') ? val.width : val.height
      await nextTick()
      handleCenter()
    }
  },
  {
    immediate: true
  }
)

// 修改状态
const handleSetState = (newState: Partial<StageState>) => {
  Object.entries(newState).forEach(([key, value]) => {
    state[key] = value
  })
}

// 居中
const handleCenter = () => {
  canvasRef.value?.initScale()
  canvasRef.value?.initStagePosition()
}

// 原始尺寸
const setOriginSize = () => {
  state.scale = 1
  canvasRef.value?.initStagePosition()
}

const handleClick = () => {
  // 点击画布空白处
  projectStore.activePageId = props.page?.id
}

/* ====================处理框选多个组件======================== */
const selectBoxRef = ref<HTMLElement | null>(null)
const boxRef = ref<HTMLElement | null>(null)
let isMouseDown = ref(false)
let startX = 0 // 框选起始x坐标
let startY = 0 // 框选起始y坐标
let workspaceLeft = 0
let workspaceTop = 0
// 鼠标按下
const handleMouseDown = (e: MouseEvent) => {
  const target = e?.target as Element | null
  if (
    target?.closest('.stage-title') ||
    target?.closest('.edit-box') ||
    target?.closest('.component-content') ||
    target?.closest('.component-wrapper') ||
    target?.closest('.scaleplate-horizontal') ||
    target?.closest('.scaleplate-vertical') ||
    target?.closest('.refer-line-img') ||
    target?.closest('.workspace-bottom') ||
    target?.closest('.refer-line') ||
    target?.closest('.ignore-click') ||
    target?.closest('.moveable-area') ||
    target?.closest('.moveable-control') ||
    target?.closest('.moveable-edge')
  ) {
    return
  }

  // 按住ctrl键时开启框选
  if (e.ctrlKey) {
    const { top, left } = boxRef.value!.getBoundingClientRect()
    const { clientX, clientY } = e
    isMouseDown.value = true
    workspaceLeft = left
    workspaceTop = top
    startX = clientX - left
    startY = clientY - top
    selectBoxRef.value!.style.display = 'block'
    selectBoxRef.value!.style.left = `${startX}px`
    selectBoxRef.value!.style.top = `${startY}px`
  }
}
/* 鼠标移动 */
const handleMouseMove = throttle((e: MouseEvent) => {
  if (!isMouseDown.value) return
  e.preventDefault()
  const { clientX, clientY } = e
  const width = clientX - workspaceLeft - startX
  const height = clientY - workspaceTop - startY

  const left = width > 0 ? startX : clientX - workspaceLeft
  const top = height > 0 ? startY : clientY - workspaceTop

  selectBoxRef.value!.style.width = `${Math.abs(width)}px`
  selectBoxRef.value!.style.height = `${Math.abs(height)}px`
  selectBoxRef.value!.style.left = `${left}px`
  selectBoxRef.value!.style.top = `${top}px`
}, 50)
/* 鼠标抬起 */
const handleMouseUp = (e: MouseEvent) => {
  if (!isMouseDown || (startX === 0 && startY === 0)) return

  e.preventDefault()
  e.stopPropagation()
  isMouseDown.value = false
  selectBoxRef.value!.style.display = 'none'
  selectBoxRef.value!.style.width = '0'
  selectBoxRef.value!.style.height = '0'

  const { clientX, clientY } = e
  const { left: stageLeft = 0, top: stageTop = 0 } = canvasRef.value?.getPosition() || {}

  // 框选的起始位置
  const x1 = (Math.min(startX + workspaceLeft, clientX) - stageLeft) / state.scale
  const y1 = (Math.min(startY + workspaceTop, clientY) - stageTop) / state.scale
  // 框选的结束位置
  const x2 = (Math.max(startX + workspaceLeft, clientX) - stageLeft) / state.scale
  const y2 = (Math.max(startY + workspaceTop, clientY) - stageTop) / state.scale
  setTimeout(() => {
    handleSelectComponent(x1, y1, x2, y2)
  }, 0)

  // 清空临时数据
  startX = startY = workspaceLeft = workspaceTop = 0
}
/* 处理框选的组件 */
const handleSelectComponent = (startX: number, startY: number, endX: number, endY: number) => {
  const widgets = props.page?.children || []
  const select = widgets.filter((item) => {
    const { x, y, width, height } = item.props
    const minX = Math.min(startX, endX)
    const maxX = Math.max(startX, endX)
    const minY = Math.min(startY, endY)
    const maxY = Math.max(startY, endY)

    // 返回判断包裹的组件
    return x >= minX && x + width <= maxX && y >= minY && y + height <= maxY
  })

  projectStore.setSelectWidgets(select)
}
/* ====================处理框选多个组件======================== */

provide('page', props.page)
provide('state', state)
provide('pageEl', boxRef)

defineExpose({
  handleCenter
})
</script>

<style lang="less" scoped>
.workspace {
  height: 100%;
  user-select: none;
  &-top {
    flex: 1;
    position: relative;
  }
  &-bottom {
    padding: 0 20px;
    height: 24px;
    border-top: solid 1px var(--border-color);
    font-size: 12px;
    color: #666;
  }
}
.selectBox {
  display: none;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 9999;
  border: solid 1px #2c76bd;
  box-sizing: border-box;
  background-color: #2c76bd90;
  width: 0;
  height: 0;
}
:deep(.el-slider) {
  --el-slider-button-size: 10px;
}
.theme {
  :deep(.el-select__wrapper) {
    box-shadow: none;
  }
}
</style>
