<template>
  <div class="elements props" v-show="group === '图层'">
    <div
      class="flex mt-16 mb-16"
      style="justify-content: end; padding-right: 8px"
    >
      <t-tooltip content="置顶" placement="top">
        <div class="icon-box" @click="changeActivLayer('top')">
          <BacktopIcon />
        </div>
      </t-tooltip>
      <t-tooltip content="置底" placement="top">
        <div class="icon-box" @click="changeActivLayer('bottom')">
          <Download1Icon />
        </div>
      </t-tooltip>
      <t-tooltip content="上一层" placement="top">
        <div class="icon-box" @click="changeActivLayer('up')">
          <ArrowUpIcon />
        </div>
      </t-tooltip>
      <t-tooltip content="下一层" placement="top">
        <div class="icon-box" @click="changeActivLayer('down')">
          <ArrowDownIcon />
        </div>
      </t-tooltip>
      <t-tooltip :content="data.expandAll ? '折叠' : '展开'" placement="top">
        <div class="icon-box" @click="changeExpand">
          <MenuFoldIcon v-if="data.expandAll" />
          <MenuUnfoldIcon v-else />
        </div>
      </t-tooltip>
    </div>
    <t-tree
      class="flex-grow"
      ref="tree"
      activeMultiple
      :data="data.tree"
      :actived="data.actived"
      v-model:expanded="data.expanded"
      activable
      :expand-parent="true"
      style="padding: 0 4px 8px 8px"
      :scroll="{
        // rowHeight: 34,
        bufferSize: 20,
        threshold: 40,
        type: 'virtual',
      }"
    >
      <template #label="{ node }: any">
        <div class="flex middle" :class="{ gray: node.data.visible === false }">
          <template
            v-if="node.getChildren() || node.data.value.endsWith('Layer')"
          >
            <folder-open-icon class="mr-8" v-if="node.expanded" />
            <folder-icon class="mr-8" v-else />
          </template>
          <!-- <t-tooltip v-else-if="node.data.tag === 'dom'" content="DOM元素">
            <Code1Icon />
          </t-tooltip> -->
          <t-tooltip v-else :content="node.data.tag === 'dom' ? 'DOM元素' : ''">
            <control-platform-icon class="mr-8" />
          </t-tooltip>
          <t-input
            v-if="node.data.edited"
            v-model="node.data.label"
            :autofocus="true"
            style="width: 100px"
            @blur="onDescription(node)"
            @enter="onDescription(node)"
          />
          <span
            v-else
            style="width: 100px"
            @click="onActive($event, node.value)"
            @dblclick="ondblclick(node)"
            @contextmenu="oncontextmenu($event,node)"
          >
            {{ node.label }}
          </span>
        </div>
      </template>
      <template #operations="{ node }: any">
        <div
          class="flex middle operations"
          :class="{
            gray: node.data.visible === false,
            show: node.data.visible === false || node.data.locked,
          }"
          style="width: 46px; height: 16px"
        >
          <template v-if="!node.data.value.endsWith('Layer')">
            <t-tooltip
              class="mr-8"
              v-if="!node.data.locked"
              content="可编辑"
              placement="top"
            >
              <svg class="l-icon" aria-hidden="true" @click="lock(node, 1)">
                <use xlink:href="#l-unlock"></use>
              </svg>
            </t-tooltip>
            <t-tooltip
              class="mr-8"
              v-else-if="node.data.locked == 1"
              content="禁止编辑"
              placement="top"
            >
              <svg class="l-icon" aria-hidden="true" @click="lock(node, 2)">
                <use xlink:href="#l-lock"></use>
              </svg>
            </t-tooltip>
            <t-tooltip
              class="mr-8"
              v-else-if="node.data.locked == 2"
              content="禁止编辑和移动"
              placement="top"
            >
              <svg class="l-icon" aria-hidden="true" @click="lock(node, 10)">
                <use xlink:href="#l-wufayidong"></use>
              </svg>
            </t-tooltip>
            <t-tooltip
              class="mr-8"
              v-else-if="node.data.locked == 10"
              content="禁止所有事件"
              placement="top"
            >
              <svg class="l-icon" aria-hidden="true" @click="lock(node, 0)">
                <use xlink:href="#l-jinyong"></use>
              </svg>
            </t-tooltip>
          </template>
          <span v-else style="width: 24px"></span>
          <browse-icon
            v-if="node.data.visible !== false"
            @click="visible(node, false)"
          />
          <browse-off-icon v-else @click="visible(node, true)" />
        </div>
      </template>
    </t-tree>
  </div>
  <div class="elements" v-show="group === '分组'">
    <div class="groups-panel" style="padding: 8px 0">
      <div class="flex middle between" style="padding: 0 12px">
        <div class="title">分组</div>
        <t-tooltip content="新建分组" placement="top">
          <div class="icon-box" @click="addGroup">
            <AddIcon />
          </div>
        </t-tooltip>
      </div>
      <div class="groups">
        <div
          v-for="(item, i) in data.groups"
          class="flex middle between hover"
          :class="{ primary: i == data.activedGroup }"
        >
          <span
            class="flex-grow"
            v-if="i != data.editedGroup"
            @click="activeGroup(i)"
            @dblclick="
              data.activedGroup = data.editedGroup = i;
              data.group = item;
            "
          >
            {{ item }}
          </span>
          <t-input
            v-else
            v-model="data.group"
            :autofocus="true"
            @blur="setGroup"
            @enter="setGroup"
          />
          <browse-icon
            v-if="!data.hiddenGroups.includes(item)"
            @click="visibleGroup(item, false)"
          />
          <browse-off-icon v-else @click="visibleGroup(item, true)" />
          <t-popconfirm
            content="确认删除该分组吗？"
            @confirm="delGroup"
            @cancel="data.deleteGroup = undefined"
          >
            <delete-icon
              class="ml-8"
              :class="{ block: i == data.deleteGroup }"
              @click="data.deleteGroup = i"
            />
          </t-popconfirm>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onBeforeMount, onMounted, onBeforeUnmount, reactive, ref } from 'vue';
import { MessagePlugin } from 'tdesign-vue-next';

import { LockState, Pen, isDomShapes } from '@meta2d/core';
import { getPenTree, inTreePanel, setChildrenVisible } from '@/services/common';
import {
  FolderOpenIcon,
  FolderIcon,
  ControlPlatformIcon,
  BrowseIcon,
  BrowseOffIcon,
  DeleteIcon,
  AddIcon,
  Code1Icon,
  BacktopIcon,
  Download1Icon,
  ArrowDownIcon,
  ArrowUpIcon,
  MenuUnfoldIcon,
  MenuFoldIcon,
} from 'tdesign-icons-vue-next';

const props = defineProps<{
  group: string;
}>();

const tree = ref<any>(null);
const data = reactive<any>({
  tree: [],
  actived: [],
  groups: [],
  hiddenGroups: [],
  expandAll: false,
  expanded: [],
});

onMounted(() => {
  meta2d.on('opened', getTree);
  meta2d.on('add', getTree);
  meta2d.on('undo', getTree);
  meta2d.on('redo', getTree);
  meta2d.on('delete', getTree);
  meta2d.on('combine', getTree);
  meta2d.on('click', getActived);
  meta2d.on('paste', getActived);
  meta2d.on('layer', layerChange);
  meta2d.on('active', getActived);

  if (inTreePanel.timer) {
    clearTimeout(inTreePanel.timer);
    inTreePanel.timer = undefined;
  }
  inTreePanel.value = true;

  getTree();
  getActived();

  const d = meta2d.store.data as any;
  if (!d.groups) {
    d.groups = [];
  }
  data.groups = d.groups;
  getHiddenGroups();
});

const getTree = () => {
  data.tree = getPhysicalTree();
};

const getPhysicalTree = () => {
  const pens = meta2d.store.data.pens;
  const imageLayer = [];
  const mainLayer = [];
  const imageBottomLayer = [];
  const templateLayer = [];
  const doms = [];
  for (let i = pens.length - 1; i >= 0; i--) {
    if (pens[i].parentId) {
      continue;
    }
    if (
      pens[i].name.endsWith('Dom') ||
      isDomShapes.includes(pens[i].name) ||
      meta2d.store.options.domShapes.includes(pens[i].name)
    ) {
      //dom图元根据层级来决定
      const node = calcElem(pens[i]);
      node.tag = 'dom';
      doms.push(node);
    } else if (pens[i].canvasLayer === 1) {
      //模版层
      templateLayer.push(calcElem(pens[i]));
    } else if (pens[i].name === 'image' || pens[i].image) {
      if (pens[i].canvasLayer === 2) {
        //底层图片绘制层
        imageBottomLayer.push(calcElem(pens[i]));
      } else if (pens[i].canvasLayer === 3) {
        //主画布层
        mainLayer.push(calcElem(pens[i]));
      } else {
        //上层图片绘制层
        imageLayer.push(calcElem(pens[i]));
      }
    } else {
      //主画布层
      mainLayer.push(calcElem(pens[i]));
    }
  }

  const list = [
    {
      label: '上层图片层', //4
      value: 'imageLayer',
      children: imageLayer,
      zIndex: 3.5,
    },
    {
      label: '主画布层', //3
      value: 'mainLayer',
      children: mainLayer,
      zIndex: 2.5,
    },
    {
      label: '底层图片层', //2
      value: 'imageBottomLayer',
      children: imageBottomLayer,
      zIndex: 1.5,
    },
    {
      label: '模版层', //1
      value: 'templateLayer',
      children: templateLayer,
      zIndex: 0.5,
    },
  ];
  list.push(...doms);
  list.sort((a, b) => b.zIndex - a.zIndex);
  return list;
};

const getPenLayer = (pen: Pen) => {
  if (
    pen.name.endsWith('Dom') ||
    isDomShapes.includes(pen.name) ||
    meta2d.store.options.domShapes.includes(pen.name)
  ) {
    return 'dom';
  } else if (pen.canvasLayer === 1) {
    //模版层
    return 'templateLayer';
  } else if (pen.name === 'image' || pen.image) {
    if (pen.canvasLayer === 2) {
      //底层图片绘制层
      return 'imageBottomLayer';
    } else if (pen.canvasLayer === 3) {
      //主画布层
      return 'mainLayer';
    } else {
      //上层图片绘制层
      return 'imageLayer';
    }
  } else {
    //主画布层
    return 'mainLayer';
  }
};

const layerChange = () => {
  getTree();
  // setTimeout(() => {

  //   if (data.actived && data.actived.length) {
  //     const element = document.body.querySelector(
  //       `[data-value="${data.actived[0]}"]`
  //     );
  //     const layer = getPenLayer(meta2d.store.active[0]);
  //     data.expanded = [layer];
  //     if (element) {
  //       element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  //     } else {
  //       let index = data.tree.findIndex((item) => item.value === layer);
  //       let innerIndex = data.tree[index]?.children.findIndex(
  //         (item) => item.value === meta2d.store.active[0].id
  //       );
  //       setTimeout(() => {
  //         tree.value?.scrollToElement({ index: index + innerIndex });
  //       }, 500);
  //     }
  //   }
  // }, 500);
};

const changeActivLayer = (key: string) => {
  if (meta2d.store.active && meta2d.store.active.length) {
    meta2d[key]();
  } else {
    MessagePlugin.info('请先选中图元');
  }
};

const changeExpand = () => {
  data.expandAll = !data.expandAll;
  if (data.expandAll) {
    data.expanded = data.tree.map((item) => item.value);
  } else {
    data.expanded = [];
  }
};
const getHiddenGroups = () => {
  data.groups.forEach((item) => {
    if (
      meta2d.store.data.pens.some(
        (pen) =>
          !pen.parentId && pen.tags?.includes(item) && pen.visible === false
      )
    ) {
      data.hiddenGroups.push(item);
    }
  });
};

let getActiveFlag = false; //点击画布导致的active还是结构中选择导致的active

const getActived = () => {
  if (getActiveFlag) {
    getActiveFlag = false;
    return;
  }
  //TODO加个异步？等展开完成后再滚动
  data.actived = [];
  if (meta2d.store.active && meta2d.store.active.length) {
    for (const pen of meta2d.store.active) {
      data.actived.push(pen.id);
    }

    const element = document.body.querySelector(
      `[data-value="${data.actived[0]}"]`
    );
    const layer = getPenLayer(meta2d.store.active[0]);
    data.expanded = [layer];
    if (element) {
      // console.log("element",element);
      element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    } else {
      // setTimeout(() => {
      //   const element = document.body.querySelector(
      //     `[data-value="${data.actived[0]}"]`
      //   );
      //   element && element.scrollIntoView({ block: 'center' });
      // }, 500);
      // let pens = meta2d.store.data.pens.filter((pen) => !pen.parentId);
      // let index = pens.findIndex((item) => item.id === meta2d.store.active[0].id);
      // let index = data.tree.findIndex(
      //   (item) => item.value === meta2d.store.active[0].id
      // );
      let index = data.tree.findIndex((item) => item.value === layer);
      let innerIndex = data.tree[index]?.children.findIndex(
        (item) => item.value === meta2d.store.active[0].id
      );
      // tree.value?.scrollTo()
      // console.log("index",index,innerIndex,data.tree);
      setTimeout(() => {
        tree.value?.scrollToElement({ index: index + innerIndex });
      }, 500);
    }
  }
};

const calcElem = (node: Pen) => {
  if (!node) {
    return;
  }

  const elem: any = {
    label: (node as any).description || node.name,
    value: node.id,
    locked: node.locked,
    visible: node.visible,
    tag: (node as any).tag,
    zIndex: node.calculative.zIndex !== undefined ? node.calculative.zIndex : 5,
  };

  if (!node.children) {
    return elem;
  }

  elem.children = [];
  for (const id of node.children) {
    const child = calcElem(meta2d.store.pens[id]);
    child && elem.children.push(child);
  }

  return elem;
};

const onActive = (e,value: any) => {
  if (!value || value.endsWith('Layer')) {
    return;
  }

  if(e.ctrlKey){
    if(data.actived.includes(value)){
      data.actived = data.actived.filter((item) => item !== value);
    }else{
      data.actived.push(value);
    }
  }else{
    data.actived = [value];
  }
  getActiveFlag = true;
  if(data.actived.length > 1){
    let pens = [];
    data.actived.forEach((item) => {
      pens.push(meta2d.store.pens[item]);
    });
    meta2d.active(pens, true);
  }else{   
      const pen = meta2d.store.pens[value];
      meta2d.active([pen], true);
      if (!pen.calculative?.inView) {
      meta2d.gotoView(pen);
      meta2d.resize();
    }
  }

  meta2d.render();
};

const ondblclick = (node: any) => {
  if (node.data.value.endsWith('Layer')) {
    return;
  } else {
    node.data.edited = true;
  }
};

const oncontextmenu = (ev,node: any) => {
  ev.preventDefault();
  ev.stopPropagation();
  let id = node.data.value;
  if(meta2d.store.active[0].id !== id){
    return;
  }
  let e = {
    clientX:ev.clientX ,
    clientY:ev.clientY
  }
  meta2d.emit('contextmenu',{e})
}

const lock = (node: any, v: LockState) => {
  node.data.locked = v;
  meta2d.setValue({
    id: node.value,
    locked: v,
  });
};

const visible = (node: any, v: boolean) => {
  node.data.visible = v;
  if (node.data.value.endsWith('Layer')) {
    if (node.data.value === 'imageLayer') {
      meta2d.canvas.canvasImage.canvas.style.display = v ? 'block' : 'none';
    } else if (node.data.value === 'mainLayer') {
      meta2d.canvas.canvas.style.display = v ? 'block' : 'none';
    } else if (node.data.value === 'imageBottomLayer') {
      meta2d.canvas.canvasImageBottom.canvas.style.display = v
        ? 'block'
        : 'none';
    } else if (node.data.value === 'templateLayer') {
      meta2d.canvas.canvasTemplate.canvas.style.display = v ? 'block' : 'none';
    }
    return;
  }
  setChildrenVisible(node, v);
  const pen = meta2d.findOne(node.value);
  pen && meta2d.setVisible(pen, v);
  meta2d.render();
};

const visibleGroup = (item, v: boolean) => {
  if (v) {
    let index = data.hiddenGroups.indexOf(item);
    if (index !== -1) {
      data.hiddenGroups.splice(index, 1);
    }
  } else {
    data.hiddenGroups.push(item);
  }
  let pens = meta2d.store.data.pens.filter(
    (pen) => !pen.parentId && pen.tags?.includes(item)
  );
  pens.forEach((pen) => {
    meta2d.setValue(
      { id: pen.id, visible: v },
      { render: false, doEvent: false }
    );
  });
  meta2d.render();
};

const onDescription = (node: any) => {
  node.data.edited = false;
  node.setData({ label: node.data.label });
  meta2d.setValue({
    id: node.value,
    description: node.data.label,
  });
};

const addGroup = () => {
  const i = data.groups.length + 1;
  data.group = '组' + i;
  data.groups.push(data.group);
  data.activedGroup = data.editedGroup = i;
};

const activeGroup = (i: number) => {
  data.activedGroup = i;
  const group = data.groups[i];
  const pens: Pen[] = [];
  for (const item of meta2d.store.data.pens) {
    if (item.tags?.includes(group)) {
      pens.push(item);
    }
  }
  meta2d.active(pens, false);
  meta2d.render();
};

const setGroup = () => {
  if (data.groups[data.editedGroup] === data.group) {
    data.editedGroup = undefined;
    return;
  }

  if (data.groups.includes(data.group)) {
    MessagePlugin.error('已经存在相同分组！');
    return;
  }

  for (const item of meta2d.store.data.pens) {
    // @ts-ignore
    if (item.group === data.groups[data.editedGroup]) {
      // @ts-ignore
      item.group === data.group;
    }
  }

  data.groups[data.editedGroup] = data.group;
  data.editedGroup = undefined;
};

const delGroup = () => {
  for (const item of meta2d.store.data.pens) {
    // @ts-ignore
    if (item.group === data.groups[data.deleteGroup]) {
      // @ts-ignore
      delete item.group;
    }
  }
  data.groups.splice(data.deleteGroup, 1);
  data.deleteGroup = undefined;
};

onBeforeUnmount(() => {
  meta2d.off('opened', getTree);
  meta2d.off('add', getTree);
  meta2d.off('undo', getTree);
  meta2d.off('redo', getTree);
  meta2d.off('delete', getTree);
  meta2d.off('combine', getTree);
  meta2d.off('click', getActived);
  meta2d.off('paste', getActived);
  meta2d.off('layer', layerChange);
  meta2d.off('active', getActived);

  inTreePanel.timer = setTimeout(() => {
    inTreePanel.value = false;
  }, 500);
});
</script>
<style lang="postcss" scoped>
.elements {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 90px);
  background: var(--color-background-active);


  & > * {
    overflow-y: auto;
    width: 100%;
  }
  .t-tree {
    /* .t-tag {
      background-color: #4583ff33;
      position: absolute;
      right: 45px;
      width: 45.6px;
      height: 21.6px;
      font-size: 10px;
      line-height: 14px;
      transform: scale(0.83333);
      transform-origin: 0 0;
    } */
  }
  .groups-panel {
    flex-shrink: 0;
    height: 100%;
    /* height: calc(100% - 55px); */
    border-top: 1px solid var(--color-border-input);
    padding: 8px 12px;
  }

  .groups {
    height: calc(100% - 55px);

    /* height: calc(100% - 24px); */
    overflow-y: auto;
    padding: 8px;
    & > div {
      height: 32px;
      line-height: 32px;
      padding: 0 8px;

      svg {
        display: none;
        &.block {
          display: block;
        }
      }

      &:hover {
        svg {
          display: block;
        }
        background: var(--color-background-input);
      }
    }
  }
}
.icon-box {
  width: 24px;
  height: 24px;
  margin: 4px;
  text-align: center;
  line-height: 24px;
  border-radius: 4px;
  &:hover {
    background: var(--td-brand-color-light);
  }
  .t-icon {
    width: 14px;
    height: 14px;
  }
}
</style>
