<template>
  <Moveable
    v-if="pageId && pageId === projectStore.activePageId"
    :target="moveableTarget"
    :draggable="canTransformSelection"
    :resizable="canTransformSelection"
    :groupable="isGroupSelection"
    :rotatable="false"
    :padding="2"
    :container="rootContainer"
    :useMutationObserver="true"
    :useResizeObserver="true"
    :throttleDrag="1"
    :throttleResize="1"
    :throttleRotate="1"
    :snappable="true"
    :snapDirections="{
      top: true,
      left: true,
      bottom: true,
      right: true,
      center: true,
      middle: true
    }"
    :elementSnapDirections="{
      top: true,
      left: true,
      bottom: true,
      right: true,
      center: true,
      middle: true
    }"
    :maxSnapElementGuidelineDistance="100"
    :elementGuidelines="getElementGridelines"
    :verticalGuidelines="verticalGuidelines"
    :horizontalGuidelines="horizontalGuidelines"
    :controlPadding="4"
    :linePadding="10"
    :edge="true"
    :individualGroupable="isIndividualGroupable"
    :individualGroupableProps="isIndividualGroupable ? individualGroupableProps : undefined"
    @render="onRender"
    @drag="onDrag"
    @resize="onResize"
    @resizeEnd="onResizeEnd"
    @dragStart="onDragStart"
    @dragEnd="onDragEnd"
    @dragGroup="onDragGroup"
    @dragGroupEnd="onDragGroupEnd"
    @resizeGroup="onResizeGroup"
    @resizeGroupEnd="onResizeGroupEnd"
    @rotateEnd="onRotateEnd"
  />
</template>

<script setup lang="ts">
import { computed, ref, inject, watch } from 'vue'
import Moveable from 'vue3-moveable'
import { useProjectStore } from '@/store/modules/project'
import { useMutationObserver } from '@vueuse/core'
import { useAppStore } from '@/store/modules/app'
import componentMap from '@/lvgl-widgets'

import type { StageState } from './type'
import { has } from 'lodash-es'
import { Page } from '@/types/page'
import { BaseWidget } from '@/types/baseWidget'

defineProps<{
  // 父级容器 拖拽缩放设置
  rootContainer: HTMLElement
  pageId?: string
}>()

const pageState = inject<StageState>('state')
const pageEl = inject<HTMLElement>('pageEl')
const elements = ref<HTMLElement[]>([])
const projectStore = useProjectStore()
const appStore = useAppStore()
const isGroupSelection = computed(() => elements.value.length > 1)
const isIndividualGroupable = computed(() => elements.value.length === 1)
const canTransformSelection = computed(() => {
  return (
    projectStore.activeWidgets.length > 0 &&
    projectStore.activeWidgets.every((item) => !hasLockedWidgetTree(item))
  )
})
const moveableTarget = computed<HTMLElement | HTMLElement[] | null>(() => {
  if (isGroupSelection.value) {
    return elements.value
  }

  return elements.value[0] ?? null
})

// 吸附附近元素
const elementGridelines = ref<Element[]>([])
// 获取吸附附近元素
const getElementGridelines = computed(() => {
  const ids = projectStore.activeWidgets.map((item) => item.id)
  return elementGridelines.value.filter((el) => {
    const id = el.attributes.getNamedItem('widget-id')?.value
    return id && !ids.includes(id)
  })
})
// 垂直辅助线
const verticalGuidelines = computed(() => {
  return (
    (pageState?.showReferenceLine &&
      projectStore.activePage?.referenceLine
        .filter((item) => item.type === 'horizontal')
        .map((item) => item.value)) ||
    []
  )
})
// 水平辅助线
const horizontalGuidelines = computed(() => {
  return (
    (pageState?.showReferenceLine &&
      projectStore.activePage?.referenceLine
        .filter((item) => item.type === 'vertical')
        .map((item) => item.value)) ||
    []
  )
})

// 监听选中元素
watch(
  () => projectStore.activeWidgets,
  () => {
    elements.value = []
    const ids = projectStore.activeWidgets.map((item) => item.id)
    document.querySelectorAll('[widget-id]').forEach((el) => {
      const id = el.attributes.getNamedItem('widget-id')?.value
      if (id && ids.includes(id)) {
        elements.value.push(el as HTMLElement)
      }
    })
  },
  {
    deep: true
  }
)

// 监听页面节点变化 设置元素辅助线
useMutationObserver(
  pageEl,
  (mutations) => {
    mutations.forEach(() => {
      const els = document.querySelectorAll('.widget-node')
      elementGridelines.value = []
      els.forEach((el) => {
        elementGridelines.value.push(el)
      })
    })
  },
  {
    childList: true,
    subtree: true
  }
)
// 临时层级
const zIndex = ref()

const individualGroupableProps = (element: HTMLElement | SVGElement | null | undefined) => {
  const widgetId = element?.getAttribute('widget-id') || ''
  if (widgetId && hasLockedWidgetTree(projectStore.activeWidgetMap[widgetId])) {
    return { draggable: false, resizable: false, rotatable: false }
  }

  const widgetType = element?.getAttribute('widget-type') || ''
  if (['lv_checkbox', 'qrcode'].includes(widgetType)) {
    return { resizable: false }
  }
  if (['barcode'].includes(widgetType)) {
    return {
      draggable: true,
      resizable: true,
      renderDirections: ['n', 's'],
      edge: ['n', 's']
    }
  }
  if (['lv_image'].includes(widgetType)) {
    return { rotatable: true }
  }
  // 不拖拽
  if (element?.getAttribute('ignore-drag') === 'true') {
    return { draggable: false }
  }

  return {
    draggable: true,
    resizable: true
  }
}

// 获取缩放值
const getScale = (widget: Page | BaseWidget) => {
  if (!widget.props?.openScale) return 1

  return (widget.props?.scale ?? 256) / 256
}

const hasLockedWidgetTree = (widget?: BaseWidget | Page): boolean => {
  return (
    !!widget &&
    (!!widget.locked || !!widget.children?.some((child) => hasLockedWidgetTree(child)))
  )
}

// 拖拽开始
const onDragStart = (e) => {
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return false
  zIndex.value = e.target.style.zIndex
  e.target.style.zIndex = 999
  appStore.draging = true
}
// 渲染节点拖拽
const onDrag = (e) => {
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
  // 当前选中节点整体移动
  e.target.style.transform = e.transform
}
// 拖拽结束
const onDragEnd = (e) => {
  e.target.style.zIndex = zIndex.value
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) {
    appStore.draging = false
    return
  }
  if (id && projectStore.activeWidgetMap[id] && e?.lastEvent?.translate) {
    projectStore.activeWidgetMap[id].props.x = Math.round(e.lastEvent.translate[0])
    projectStore.activeWidgetMap[id].props.y = Math.round(e.lastEvent.translate[1])
  }
  appStore.draging = false
}
// 渲染节点缩放
const onResize = (e) => {
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
  e.target.style.width = `${e.width}px`
  e.target.style.height = `${e.height}px`
  e.target.style.transform = e.drag.transform
}
// 节点缩放完成
const onResizeEnd = (e) => {
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
  if (e.lastEvent && id && projectStore.activeWidgetMap[id]) {
    const scale = getScale(projectStore.activeWidgetMap[id])
    let width = Math.round(e.lastEvent.width / scale)
    let height = Math.round(e.lastEvent.height / scale)

    // 触发控件监听事件
    const onChangeSize = componentMap[projectStore.activeWidgetMap[id].type]?.onChangeSize
    if (typeof onChangeSize === 'function') {
      const originWidth = projectStore.activeWidgetMap[id].props.width
      const originHeight = projectStore.activeWidgetMap[id].props.height
      const result = onChangeSize(projectStore.activeWidgetMap[id].props, {
        originWidth,
        currentWidth: width,
        originHeight,
        currentHeight: height
      })
      width = result?.width ?? width
      height = result?.height ?? height
    }

    if (projectStore.activeWidgetMap[id].props.width !== undefined) {
      projectStore.activeWidgetMap[id].props.width = width
    } else {
      e.target.style.width = ''
    }
    if (projectStore.activeWidgetMap[id].props.height !== undefined) {
      projectStore.activeWidgetMap[id].props.height = height
    } else {
      e.target.style.height = ''
    }

    // 带可选固定高度控件
    if (has(projectStore.activeWidgetMap[id].props, 'fixedHeight')) {
      projectStore.activeWidgetMap[id].props.fixedHeight = true
    }
    // 设置位置
    if (e.lastEvent.drag?.translate) {
      projectStore.activeWidgetMap[id].props.x = Math.round(e.lastEvent.drag.translate[0])
      projectStore.activeWidgetMap[id].props.y = Math.round(e.lastEvent.drag.translate[1])
    }
  }
}
// 渲染节点事件
const onRender = (e) => {
  e.target.style.cssText += e.cssText
}
// 节点组拖拽
const onDragGroup = ({ events }) => {
  events.forEach((ev) => {
    const id = ev.target.attributes['widget-id']?.value
    if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
    ev.target.style.transform = ev.transform
  })
}
// 节点组缩放
const onResizeGroup = ({ events }) => {
  events.forEach((ev) => {
    const id = ev.target.attributes['widget-id']?.value
    if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
    ev.target.style.width = `${ev.width}px`
    ev.target.style.height = `${ev.height}px`
    ev.target.style.transform = ev.drag.transform
  })
}
// 节点组拖拽结束
const onDragGroupEnd = ({ events }) => {
  events.forEach((ev) => {
    const id = ev.target.attributes['widget-id']?.value
    if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
    if (id && projectStore.activeWidgetMap[id] && ev?.lastEvent?.translate) {
      projectStore.activeWidgetMap[id].props.x = Math.round(ev.lastEvent.translate[0])
      projectStore.activeWidgetMap[id].props.y = Math.round(ev.lastEvent.translate[1])
    }
  })
}
// 节点组缩放结束
const onResizeGroupEnd = ({ events }) => {
  events.forEach((ev) => {
    const id = ev.target.attributes['widget-id']?.value
    if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
    if (ev.lastEvent && id && projectStore.activeWidgetMap[id]) {
      const scale = getScale(projectStore.activeWidgetMap[id])
      let width = Math.round(ev.lastEvent.width / scale)
      let height = Math.round(ev.lastEvent.height / scale)

      // 触发控件监听事件
      const onChangeSize = componentMap[projectStore.activeWidgetMap[id].type]?.onChangeSize
      if (typeof onChangeSize === 'function') {
        const originWidth = projectStore.activeWidgetMap[id].props.width
        const originHeight = projectStore.activeWidgetMap[id].props.height
        const result = onChangeSize(projectStore.activeWidgetMap[id].props, {
          originWidth,
          currentWidth: width,
          originHeight,
          currentHeight: height
        })
        width = result?.width ?? width
        height = result?.height ?? height
      }

      if (projectStore.activeWidgetMap[id].props.width !== undefined) {
        projectStore.activeWidgetMap[id].props.width = width
      } else {
        ev.target.style.width = ''
      }
      if (projectStore.activeWidgetMap[id].props.height !== undefined) {
        projectStore.activeWidgetMap[id].props.height = height
      } else {
        ev.target.style.height = ''
      }

      // 带可选固定高度控件
      if (has(projectStore.activeWidgetMap[id].props, 'fixedHeight')) {
        projectStore.activeWidgetMap[id].props.fixedHeight = true
      }
      // 设置位置
      if (ev.lastEvent.drag?.translate) {
        projectStore.activeWidgetMap[id].props.x = Math.round(ev.lastEvent.drag.translate[0])
        projectStore.activeWidgetMap[id].props.y = Math.round(ev.lastEvent.drag.translate[1])
      }
    }
  })
}

// 旋转结束
const onRotateEnd = (e) => {
  const id = e.target.attributes['widget-id']?.value
  if (id && hasLockedWidgetTree(projectStore.activeWidgetMap[id])) return
  if (e.lastEvent && id && projectStore.activeWidgetMap[id]) {
    // 设置位置
    projectStore.activeWidgetMap[id].props.rotation = Math.round(e.lastEvent.rotate)
  }
}
</script>

<style less>
/* .moveable-control-box {
  --moveable-color: #333 !important;
} */
.moveable-origin {
  display: none;
}
</style>
