<template>
  <div ref="container" class="vtj-designer">
    <Viewport
      :mode="(mode as any)"
      :width="wrapperRect.width"
      :height="wrapperRect.height">
      <iframe v-show="project.current" ref="iframe" frameborder="0"></iframe>
      <div
        v-show="nodeDropping.show"
        class="vtj-designer__dropping"
        :class="`is-${nodeDropping.type}`"
        :style="nodeDropping.style"></div>

      <div
        v-show="nodeHover.show"
        class="vtj-designer__hover"
        :style="nodeHover.style">
        <span
          class="vtj-designer__hover-title"
          :class="`is-${nodeHover.position}`"
          >{{ nodeHover.title }}: <i> {{ nodeHover.id }}</i></span
        >
      </div>

      <div
        v-if="nodeSelected.show"
        class="vtj-designer__selected"
        :style="nodeSelected.style">
        <Actions
          :position="nodeSelected.position"
          :title="nodeSelected.title"
          :node="(nodeSelected.node as Block | Node)"
          :path="(nodeSelected.path as INode[])"
          @action="handleAction"></Actions>
      </div>
    </Viewport>
    <ElEmpty
      v-if="!project.current"
      description="请在文档管理器新建或打开文件"></ElEmpty>
  </div>
</template>
<script lang="ts" setup>
import { Ref, ref, computed, onUnmounted } from 'vue';
import useDesigner from '../hooks/useDesigner';
import Actions from '../parts/Actions.vue';
import Viewport from '../views/Viewport.vue';
import { ElEmpty } from 'element-plus';
import {
  Block,
  Node,
  INode,
  emitter,
  EVENT_VIEWPORT_MODE_CHANGE
} from '@vtj/engine';
import { useResizeObserver } from '@vueuse/core';
const iframe = ref<HTMLIFrameElement>();
const container = ref();
const { project, hover, selected, dropping, setHover, setSelected } =
  useDesigner(iframe as Ref<HTMLIFrameElement>);

const wrapperRect = ref({ width: 0, height: 0 });

const mode = ref('pc');

useResizeObserver(container, (entries) => {
  const entry = entries[0];
  wrapperRect.value = entry.contentRect;
});

const handleViewPortChange = (value: any) => {
  mode.value = value;
};

emitter.on(EVENT_VIEWPORT_MODE_CHANGE, handleViewPortChange);

onUnmounted(() => {
  emitter.off(EVENT_VIEWPORT_MODE_CHANGE, handleViewPortChange);
});

function getPosition(rect: any, leftPriority: boolean) {
  const { top, height, width, left } = rect || {};
  if (height > 100 && width > 200) {
    return 'inner';
  }

  let h, v;
  v = top > 30 ? 'top' : 'bottom';
  h = leftPriority ? 'left' : left < 300 && width < 300 ? 'left' : 'right';

  return [h, v].join('-');
}

const nodeHover = computed(() => {
  const show = !!hover.value;
  const rect = hover.value?.rect || { left: 0, top: 0, width: 0, height: 0 };
  const node = hover.value?.node;
  return {
    show,
    style: {
      left: `${rect.left}px`,
      top: `${rect.top}px`,
      width: `${rect.width}px`,
      height: `${rect.height}px`
    },
    title: node?.name || '',
    id: node?.id || '',
    position: getPosition(rect, true)
  };
});

const nodeDropping = computed(() => {
  const show = !!dropping.value;
  let { left, top, width, height } = dropping.value?.rect || {
    left: 0,
    top: 0,
    width: 0,
    height: 0
  };

  let rect = {
    left,
    top,
    width,
    height
  };

  const type = (dropping.value as any)?.type || '';
  if (type === 'left') {
    rect = {
      left: 0,
      top,
      width: 0,
      height
    };
  }
  if (type === 'right') {
    rect = {
      left: left + width - 4,
      top,
      width: 0,
      height
    };
  }
  if (type === 'bottom') {
    rect = {
      left,
      top: top + height - 4,
      width,
      height: 0
    };
  }
  if (type === 'top') {
    rect = {
      left,
      top: top,
      width,
      height: 0
    };
  }
  return {
    show,
    type: type || '',
    style: {
      left: `${rect.left}px`,
      top: `${rect.top}px`,
      width: `${rect.width}px`,
      height: `${rect.height}px`
    }
  };
});

const nodeSelected = computed(() => {
  const show = !!selected.value;
  const {
    rect = { left: 0, top: 0, width: 0, height: 0 },
    node,
    path
  } = selected.value || {};
  return {
    show: rect.width && rect.height,
    style: {
      left: `${rect.left}px`,
      top: `${rect.top}px`,
      width: `${rect.width}px`,
      height: `${rect.height}px`
    },
    title: node?.name || '',
    position: getPosition(rect, false),
    node,
    path
  };
});

const handleAction = (e: any) => {
  const { type, node } = e;
  switch (type) {
    case 'remove':
      selected.value = null;
      break;
    case 'move':
      if (selected.value) {
        setSelected(selected.value.node as INode);
      }
      break;
    case 'copy':
      if (node) {
        setSelected(node as INode);
      } else {
        selected.value = null;
      }
      break;
    case 'hover':
      if (node) {
        setHover(node as INode);
      }
      break;
    case 'selected':
      if (node) {
        setSelected(node as INode);
      }
      break;
    default:
      break;
  }
};
</script>
