<template>
  <div class="overflowWrapper" :style="{ width: props.domWidth + 'px', height: domHeight + 'px' }">
    <div
      class="scaleWrapper"
      :style="{
        scale: scale,
        width: props.canvasSize.width + 'px',
        height: props.canvasSize.height + 'px',
      }"
    >
      <v-stage
        :config="configKonva"
        @mouse-down="handleStageMouseDown"
        @mouse-move="handleStageMouseMove"
        ref="stageRef"
      >
        <v-layer>
          <FenceItem
            :fenceGroups="fenceGroups"
            :draggable="!drawingGroupId"
            @select-group="handleSelectGroup"
            :is-edit="isEdit"
            :current-group-id="currentGroupId"
          />
        </v-layer>
      </v-stage>
    </div>
  </div>
</template>
<script lang="ts" setup>
  import Konva from 'konva';
  import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
  import FenceItem from './FenceItem.vue';
  import { createCircleConfigItem, createGroupConfig } from './utils';
  import { FenceGroup } from './types';
  import { ElMessage } from 'element-plus';
  import { GROUP_NAME } from './constants';

  const props = defineProps<{
    /** 电子围栏的坐标 */
    linePoints: [number, number][][];
    /** 画布的大小 */
    canvasSize: { width: number; height: number };
    /** dom的真实尺寸 */
    domWidth: number;
  }>();

  const scale = computed(() => {
    return props.domWidth / props.canvasSize.width;
  });

  const stageRef = ref();
  const isEdit = ref(false);

  const fenceGroups = ref<FenceGroup[]>([]);

  /** 当前正在画的多边形的groupId */
  const drawingGroupId = ref('');
  /** 当前选中的多边形groupId，点击、拖拽、画线都会给它赋值 */
  const currentGroupId = ref('');

  watch(
    () => props.linePoints,
    (newLinePoints) => {
      const configs: FenceGroup[] =
        newLinePoints.map((points) => {
          const flattenedPoints = points.reduce((total, next) => {
            return [...total, ...next];
          }, [] as number[]);
          return createGroupConfig(flattenedPoints, scale.value);
        }) || [];
      fenceGroups.value = configs;
    },
    {
      immediate: true,
    },
  );

  onMounted(() => {
    /** 取消默认的右键 */
    document.oncontextmenu = function () {
      return false;
    };
  });

  onUnmounted(() => {
    /** 取消默认的右键 */
    document.oncontextmenu = function () {
      return true;
    };
  });

  const configKonva = computed(() => {
    return props.canvasSize;
  });

  const canvasRatio = computed(() => {
    const size = props.canvasSize;
    if (!size) return 1;
    return size.height / size.width;
  });

  const domHeight = computed(() => {
    return props.domWidth * canvasRatio.value;
  });

  const handleStageMouseDown = (e) => {
    if (!isEdit.value) return;
    /**
     * parent存在，说明点击的不是stage
     * !drawingGroupId，说明当前不处于绘制多边形中
     * 这两种情况，都不能执行stage的点击事件，要执行点击对象的默认事件
     */
    if (e.target.parent && !drawingGroupId.value) return;
    const stage = e.currentTarget as Konva.Stage;
    // 获取当前鼠标相对舞台的位置
    const mousePosition = stage.getPointerPosition();
    if (!mousePosition?.x || !mousePosition?.y) return;
    const point = [mousePosition.x, mousePosition.y] as [number, number];

    /** 如果还没开始画线，那么增加第一个点 */
    if (!drawingGroupId.value) {
      const groupConfig = createGroupConfig(point, scale.value);
      drawingGroupId.value = groupConfig.uid;
      currentGroupId.value = groupConfig.uid;
      groupConfig._temp.points = point;
      fenceGroups.value.push(groupConfig);
    } else {
      /** 右键点击，取消最后一个点 */
      if (e.evt.button === 2) {
        /** 否则就追加点 */
        const groupConfig = fenceGroups.value.find((x) => x.uid === drawingGroupId.value);
        if (!groupConfig) {
          console.error('drawingGroupId无效', drawingGroupId.value);
          return;
        }
        if ((groupConfig._temp.points.length || 0) <= 4) {
          ElMessage({
            message: '顶点数必须大于2个！',
            type: 'warning',
            center: true,
            duration: 1000,
          });
          /** 要把当前的group给删除掉 */
          fenceGroups.value = fenceGroups.value.filter((x) => x.uid !== drawingGroupId.value);
          groupConfig.lineConfig.points = [];
          groupConfig.circleConfigs = [];
          currentGroupId.value = '';
        } else {
          groupConfig.lineConfig.points = groupConfig._temp.points;
        }
        drawingGroupId.value = '';
        groupConfig._temp.points = [];
        return;
      }
      /** 否则就追加点 */
      const groupConfig = fenceGroups.value.find((x) => x.uid === drawingGroupId.value);
      if (!groupConfig) {
        console.error('drawingGroupId无效', drawingGroupId.value);
        return;
      }
      const tempPoints = groupConfig._temp?.points || [];
      const finalPoints = [...tempPoints, ...point];
      groupConfig.lineConfig.points = finalPoints;
      groupConfig._temp.points = finalPoints;
      currentGroupId.value = groupConfig.uid;

      const circleConfig = createCircleConfigItem(
        point,
        groupConfig.circleConfigs.length,
        scale.value,
      );
      groupConfig.circleConfigs.push(circleConfig);
    }
  };

  const handleStageMouseMove = (e) => {
    if (!isEdit.value) return;
    const stage = e.currentTarget as Konva.Stage;
    /** 获取当前鼠标的坐标 */
    const mousePosition = stage.getPointerPosition();
    if (!mousePosition?.x || !mousePosition?.y) return;
    const newPoint = [mousePosition.x, mousePosition.y];
    if (drawingGroupId.value) {
      const groupConfig: FenceGroup | undefined = fenceGroups.value.find(
        (x) => x.uid === drawingGroupId.value,
      );
      if (!groupConfig) {
        console.error('drawingGroupId无效', drawingGroupId.value);
        return;
      }

      /** 如果正在画线，那么替换最后一个点 */
      const initialPoints = groupConfig.lineConfig.points as number[];
      if (groupConfig._temp.points.length > 0) {
        groupConfig.lineConfig.points = [...groupConfig._temp.points, ...newPoint];
      } else {
        groupConfig._temp.points = initialPoints;
      }
    }
  };

  const handleSelectGroup = (groupId: string) => {
    currentGroupId.value = groupId;
  };

  /** 清空所有元素 */
  const clear = () => {
    fenceGroups.value = [];
  };

  /** 删除当前选中的group项 */
  const remove = () => {
    fenceGroups.value = fenceGroups.value.filter((x) => x.uid !== currentGroupId.value);
    currentGroupId.value = '';
  };

  /** 导出为json格式 */
  const toObject = () => {
    const stage = stageRef.value.getStage();
    const fenceGroups = stage?.find('.' + GROUP_NAME);
    const gropuPoints = fenceGroups
      ?.map((item) => {
        const groupX = item.x();
        const groupY = item.y();

        const line = (item as Konva.Group).findOne(
          (x: any) => x.className === 'Line',
        ) as Konva.Line;
        const points = line?.points();
        /** 有些line对象存在，但是没有点坐标，所以要判断过滤一下 */
        if (points && points.length > 0) {
          const newPoints: number[][] = [];
          /** 存到后端的时候，只给点的坐标信息，不会给group的位置信息，所以要将点的坐标加上group的位移，才是之后点的最终坐标 */
          for (let i = 0; i < points.length; i += 2) {
            newPoints.push([Math.floor(points[i] + groupX), Math.floor(points[i + 1] + groupY)]);
          }
          return newPoints;
        }
        return null;
      })
      .filter(Boolean);
    return gropuPoints;
  };

  /** 退出编辑模式 */
  const exitEditMode = () => {
    currentGroupId.value = '';
    isEdit.value = false;
  };
  /** 进入编辑模式 */
  const setEditMode = () => {
    isEdit.value = true;
  };

  defineExpose({
    clear,
    remove,
    toObject,
    exitEditMode,
    setEditMode,
  });
</script>

<style scoped>
  .scaleWrapper {
    transform-origin: left top;
  }
  .overflowWrapper {
    overflow: hidden;
    border: 1px solid #efefef;
  }
</style>
