<template>
  <Teleport :to="`#draw-renderer`" v-if="stage">
    <transition name="pointer-fade">
      <div
        v-if="pointer"
        :style="{ transform: pointer }"
        :size="8"
        class="propertys-controller"
        ref="layout"
      >
        <Menu>
          <MenuItem v-for="menu in menus" @click="clickHandler(menu.handler)">
            <ui-icon :type="menu.icon" />
            <span>{{ menu.label }}</span>
          </MenuItem>
        </Menu>
      </div>
    </transition>
  </Teleport>
</template>

<script lang="ts" setup>
import { computed, nextTick, ref, watch, watchEffect } from "vue";
import { Transform } from "konva/lib/Util";
import { Menu, MenuItem } from "ant-design-vue";
import { shapeTreeContain, useStage, useViewerTransformConfig } from "./hook.js";
import { DC, EntityShape } from "./dec.js";

const props = defineProps<{
  target: DC<EntityShape> | undefined;
  data?: Record<string, any>;
  menus: Array<{ icon?: any; label?: string; handler: () => void }>;
}>();
const emit = defineEmits<{
  (e: "show" | "hide"): void;
}>();

const layout = ref<HTMLDivElement>();
const stage = useStage();
// const status = useMouseShapeStatus(computed(() => props.target));
const rightClick = ref(false);

const hasRClick = (ev: MouseEvent) => {
  if (ev.button !== 2) return false;
  const shape = props.target?.getNode();
  const pos = stage.value?.getNode().pointerPos;
  const layer = stage.value?.getNode().children[0];
  if (!shape || !pos || !layer) return false;
  let clickShape = layer.getIntersection(pos);
  ev.preventDefault();
  return !!clickShape && shapeTreeContain(shape, clickShape) === shape;
};

watchEffect((onCleanup) => {
  const dom = stage.value?.getStage().container();
  if (!dom) return;

  const clickHandler = async (ev: MouseEvent) => {
    const show = hasRClick(ev);
    if (show && rightClick.value) {
      rightClick.value = false;
      await nextTick();
    }
    rightClick.value = show;
  };

  dom.addEventListener("contextmenu", clickHandler);
  dom.addEventListener("pointerdown", clickHandler);
  onCleanup(() => {
    dom.removeEventListener("contextmenu", clickHandler);
    dom.removeEventListener("pointerdown", clickHandler);
  });
});

const clickHandler = (handler: () => void) => {
  handler();
  rightClick.value = false;
};

const hidden = computed(
  () =>
    !stage.value?.getStage() ||
    !props.target?.getNode() ||
    // !status.value.hover ||
    // status.value.active ||
    // transformIngShapes.value.length !== 0
    !rightClick.value
);

const move = new Transform();
const pointer = ref<string | null>(null);
const calcPointer = async () => {
  if (hidden.value) {
    pointer.value = null;
    return;
  } else if (pointer.value) {
    return;
  }
  const $stage = stage.value!.getStage();
  const mousePosition = $stage.pointerPos;
  if (!mousePosition) {
    pointer.value = null;
    return;
  }
  const $shape = props.target!.getNode();
  const shapeRect = $shape.getClientRect();

  const shapeR = shapeRect.x + shapeRect.width;
  const shapeB = shapeRect.y + shapeRect.height;
  let x = Math.min(Math.max(mousePosition.x, shapeRect.x), shapeR);
  let y = Math.min(Math.max(mousePosition.y, shapeRect.y), shapeB);

  move.reset();
  move.translate(x, y);
  pointer.value = `matrix(${move.m.join(",")})`;
  await nextTick();

  const domRect = layout.value!.getBoundingClientRect();
  x = x - domRect.width / 2;
  x = Math.max(x, shapeRect.x);

  if (x + domRect.width > shapeR) {
    x = shapeR - domRect.width;
  }
  if (y + domRect.height > shapeB) {
    y = y - domRect.height;
  }

  x = Math.max(x, 10);
  y = Math.max(y, 10);
  if (x + domRect.width > $stage.width() - 10) {
    x = $stage.width() - domRect.width - 10;
  }
  if (y + domRect.height > $stage.height() - 10) {
    y = $stage.height() - domRect.height - 10;
  }

  move.reset();
  move.translate(x, y);
  pointer.value = `matrix(${move.m.join(",")})`;
};
watch(
  () => !!pointer.value,
  (show) => {
    emit(show ? "show" : "hide");
  }
);

let timeout: any;
const resetPointer = () => {
  if (hidden.value) {
    pointer.value = null;
    return;
  } else if (pointer.value) {
    return;
  }
  clearTimeout(timeout);
  timeout = setTimeout(calcPointer, 16);
};

watch(hidden, resetPointer);
watch(useViewerTransformConfig(), () => {
  pointer.value = null;
  resetPointer();
});
// watch(() => props.data, resetPointer);
</script>

<style lang="scss">
.propertys-controller {
  pointer-events: none;
  position: absolute;
  border-radius: 4px;
  border: 1px solid #e4e7ed;
  background-color: #ffffff;
  left: 0;
  top: 0;
  overflow: hidden;
  color: #303133;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  min-width: 10px;
  padding: 5px 0;
  pointer-events: all;
  font-size: 14px;
  border: 1px solid var(--el-border-color-light);
  box-shadow: var(--el-dropdown-menu-box-shadow);
  background-color: var(--el-bg-color-overlay);
  border-radius: var(--el-border-radius-base);
  --el-menu-base-level-padding: 16px;
  --el-menu-item-height: 32px;
  --el-menu-item-font-size: 14px;

  .el-menu-item {
    align-items: center;
    padding: 5px 16px 5px 6px !important;
    color: var(--el-text-color-regular);
  }
  .el-menu-item [class^="el-icon"] {
    margin: 0;
    font-size: 1em;
  }
}

.pointer-fade-enter-active,
.pointer-fade-leave-active {
  transition: opacity 0.3s ease;
  .item {
    pointer-events: none;
  }
}
.pointer-fade-enter-from,
.pointer-fade-leave-to {
  opacity: 0;
}
</style>
