<template>
  <div
    class="component-wrapper"
    ref="componentWrapperRef"
    :style="warpperStyle"
  >
    <div class="group-box" v-if="componentData.componentType === 'group'">
      <ComponentWrapper
        v-for="item in componentData.children"
        v-show="item.visible"
        :component-data="item"
        :key="item.key"
        :style="{ zIndex: item.zIndex }"
      />
    </div>
    <Container v-bind="componentData.container" v-else>
      <component
        :is="component"
        v-bind="componentData.props"
        :width="getComponentWidth"
        :height="getComponentHeight"
      />
    </Container>
    <div v-if="showEditBox" class="edit-box" :style="editWapperStyle">
      <span class="name-tip">{{ getTip }}</span>
      <UseDraggable
        v-for="item in dragPointList"
        :key="item"
        @move="(_, e) => handleDragPoint(item, e)"
        @start="handleDragStart"
        @end="handleDragEnd"
      >
        <span
          v-if="!componentData.locked"
          class="edit-box-point"
          :class="item"
        ></span>
      </UseDraggable>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { CustomElement } from "#/project";
import { defineProps, defineAsyncComponent, computed, ref } from "vue";
import { useStageStore } from "@/store/modules/stage";
import { useProjectStore } from "@/store/modules/project";
import { useDraggable } from "@vueuse/core";
import { UseDraggable } from "@vueuse/components";
import { useAcionStore } from "@/store/modules/action";
import { asyncComponentAll, Container } from "@shalu/dashboard-ui";
import { scaleAction } from "@/utils/scale";
import { useAdsorb } from "@/hooks";

const { componentData } = defineProps<{ componentData: CustomElement }>();
// 动态引入组件
const component =
  componentData.componentType === "group"
    ? ""
    : defineAsyncComponent(asyncComponentAll[componentData.componentType as keyof typeof asyncComponentAll]);

const componentWrapperRef = ref<HTMLElement | null>(null);
const stageStore = useStageStore();
const projectStore = useProjectStore();
const actionStore = useAcionStore();
const { getMoveAdsorbInfo } = useAdsorb();
const editWapperStyle = computed(() => {
  const { width = 400, height = 260 } = componentData.container.props || {};

  return {
    transform: `scale(${1 / stageStore.scale})`,
    transformOrigin: "50% 50%",
    width: `${width * stageStore.scale}px`,
    height: `${height * stageStore.scale}px`,
    border: "1px solid #1890ff",
    left: (width / 2) * (1 - stageStore.scale) + "px",
    top: (height / 2) * (1 - stageStore.scale) + "px",
  };
});

// 组件宽--根据边距计算
const getComponentWidth = computed(() => {
  const { width = 400 } = componentData.container.props || {};
  const { paddingLeft = 0, paddingRight = 0 } =
    componentData.container.props || {};
  return width - paddingLeft - paddingRight;
});

// 组件高--根据边距计算
const getComponentHeight = computed(() => {
  const { height = 260 } = componentData.container.props || {};
  const { paddingTop = 0, paddingBottom = 0 } =
    componentData.container.props || {};
  return height - paddingTop - paddingBottom;
});

const warpperStyle = computed(() => {
  const {
    width = 400,
    height = 260,
    x,
    y,
  } = componentData.container.props || {};
  // const style = transformStyle(componentData.container?.style || {});

  return {
    width: `${width}px`,
    height: `${height}px`,
    left: x + "px",
    top: y + "px",
  };
});
// 是否显示编辑框
const showEditBox = computed(() => {
  return (
    projectStore.mode === "edit" &&
    projectStore.selectedElementKeys.includes(componentData.key)
  );
});
// 获取提示信息
const getTip = computed(() => {
  const { x, y } = componentData.container.props || {};
  return showNameTip.value
    ? componentData.name
    : `x: ${Math.round(x)} y: ${Math.round(y)}`;
});

let isPointDragFlag = false;
const showNameTip = ref(true);
let moveLeft: number;
// 拖拽移动组件
useDraggable(componentWrapperRef, {
  onMove: (position) => {
    if (isPointDragFlag) return;

    const originPosition = componentWrapperRef.value!.getBoundingClientRect();
    // 计算移动的距离
    const xMoveLength = position.x - originPosition.left;
    const yMoveLentgh = position.y - originPosition.top;

    const { newMoveX, newMoveY } = getMoveAdsorbInfo({
      moveX: xMoveLength,
      moveY: yMoveLentgh,
    });

    moveLeft = Math.max(Math.abs(newMoveX), Math.abs(newMoveY));
    // 对每个选中的组件进行移动
    projectStore.currentSelectedElements.forEach((item) => {
      const { x, y } = item.container.props || {};
      projectStore.updateElement(
        item.key,
        "container.props.x",
        Math.round(x + newMoveX)
      );
      projectStore.updateElement(
        item.key,
        "container.props.y",
        Math.round(y + newMoveY)
      );
    });
  },
  onStart: () => {
    if (!projectStore.selectedElementKeys.includes(componentData.key)) {
      projectStore.setSelectedElementKeys([componentData.key]);
    }
    showNameTip.value = false;
    moveLeft = 0;
  },
  onEnd: () => {
    showNameTip.value = true;
    moveLeft && actionStore.addRecord(); // 记录操作
  },
});

/* ===============================缩放组件==================================== */
const dragPointList = [
  "top-left",
  "top-center",
  "top-right",
  "left-center",
  "right-center",
  "bottom-left",
  "bottom-center",
  "bottom-right",
];

const startPoint = {
  x: 0,
  y: 0,
};
// 拖拽点移动 => 缩放组件
const handleDragPoint = (type: string, e: PointerEvent) => {
  const moveX = (e.x - startPoint.x) / stageStore.scale;
  const moveY = (e.y - startPoint.y) / stageStore.scale;

  startPoint.x = e.x;
  startPoint.y = e.y;

  // 对选中的组件进行缩放
  scaleAction({
    projectStore,
    type,
    moveX,
    moveY,
    elements: projectStore.currentSelectedElements,
  });
};
// 拖拽点开始
const handleDragStart = (_: any, e: PointerEvent) => {
  startPoint.x = e.x;
  startPoint.y = e.y;
  isPointDragFlag = true;
  showNameTip.value = false;
};
// 拖拽点结束
const handleDragEnd = () => {
  isPointDragFlag = false;
  showNameTip.value = true;
  actionStore.addRecord(); // 记录操作
};
</script>

<script lang="ts">
export default {
  name: "ComponentWrapper",
};
</script>

<style lang="less" scoped>
.component-wrapper {
  position: absolute;
}
.edit-box {
  position: absolute;
  &-point {
    position: absolute;
    width: 8px;
    height: 8px;
    background: #fff;
    border-radius: 50%;
    border: solid 1px @primary-color;
  }
  .name-tip {
    position: absolute;
    top: -20px;
    left: 4px;
    font-size: 12px;
    color: #fff;
    background: @primary-color;
    padding: 2px 4px;
  }
  .top-left {
    top: -4px;
    left: -4px;
    cursor: nw-resize;
  }
  .top-center {
    top: -4px;
    left: 50%;
    transform: translateX(-50%);
    transform-origin: center;
    cursor: n-resize;
  }
  .top-right {
    top: -4px;
    right: -4px;
    cursor: ne-resize;
  }
  .left-center {
    top: 50%;
    left: -4px;
    transform: translateY(-50%);
    cursor: w-resize;
  }
  .right-center {
    top: 50%;
    right: -4px;
    transform: translateY(-50%);
    cursor: e-resize;
  }
  .bottom-left {
    bottom: -4px;
    left: -4px;
    cursor: sw-resize;
  }
  .bottom-center {
    bottom: -4px;
    left: 50%;
    transform: translateX(-50%);
    cursor: s-resize;
  }
  .bottom-right {
    bottom: -4px;
    right: -4px;
    cursor: se-resize;
  }
}
</style>
