import { TreeToolbars } from "@/modules/editor/objects/Toolbars";
import { css } from "@linaria/core";
import { Image } from "@queenjs/ui";
import { useReactive } from "@queenjs/use";
import { Tree, TreeProps } from "ant-design-vue";
import { defineComponent, nextTick, watch } from "vue";
import { string, bool } from "vue-types";
import { useEditor } from "../../../..";
import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
import { TreeDataItem } from "ant-design-vue/lib/tree";
import { CompObject } from "@/modules/editor/controllers/SelectCtrl/compObj";

type TreeItem = {
  key: string;
  title: string;
  value: string;
  children: TreeItem[];
};

export const CompTree = defineComponent({
  setup() {
    const { store, actions, helper, controls } = useEditor();
    const { compUICtrl } = controls;

    const state = useReactive(() => ({
      expandedKeys: [] as string[],
      treeData() {
        const rootComp = helper.findRootComp();

        let deep = 0;
        function getCompChildren(ids: string[]): TreeItem[] {
          deep += 1;
          if (deep > 2) ids = [...ids].reverse();

          return ids.map((id) => {
            const comp = helper.findComp(id) as DesignComp;
            return {
              key: comp.id,
              title:
                comp.title ||
                compUICtrl.state.components.get(comp.compKey)?.name ||
                "未命名",
              value: comp.id,
              children: comp?.getChildIds
                ? getCompChildren(comp?.getChildIds())
                : [],
            };
          });
        }
        return getCompChildren(rootComp?.id ? [rootComp.id] : []);
      },
    }));

    watch(
      () => store.currCompId,
      () => {
        // expandedKeys需要等Tree的内部状态更新后再赋值
        nextTick(() => {
          state.expandedKeys = store.currCompId
            ? helper.getCompTrees(store.currCompId).map((comp) => comp.id)
            : [];
        });
      }
    );
    const onDrop = (info: any) => {
      const dragNode = info.dragNode; //被拖拽
      const dropNode = info.node; //拖拽落下

      const dragKey = dragNode.key;
      const dropKey = dropNode.key;

      const dragPos = dragNode.pos.split("-");
      const dropPos = dropNode.pos.split("-");

      const dragLevel = dragPos.length;
      const dropLevel = dropPos.length;
      if (
        dragLevel >= 5 ||
        dragKey == "root" ||
        dragLevel < dropLevel ||
        dragLevel - dropLevel > 1
      ) {
        return;
      }
      let parentComp: any = null;
      if (dragLevel > dropLevel) {
        parentComp = helper.findComp(dropKey);
      } else {
        parentComp = helper.findParentComp(dropKey);
      }
      const currComp = helper.findComp(dragKey);
      const currParent = helper.findParentComp(dragKey);

      if (!currComp) return;
      const currParentComp = helper.findParentComp(dragKey);
      const index = currParentComp?.children.default?.indexOf(currComp.id);
      if (index != -1) {
        currParentComp?.children.default?.splice(index as number, 1);
        helper.extendStreamCard(currParentComp?.id || "");
      }

      if (!info.dropToGap) {
        parentComp?.children.default == parentComp?.children.default || [];
        if (dragLevel <= 3) {
          parentComp?.children.default?.unshift(currComp?.id);
        } else {
          parentComp?.children.default?.push(currComp?.id);
        }
        if (currParent?.id != parentComp.id) {
          const len = parentComp?.children.default?.length;
          const index = dragLevel > 3 ? len - 1 : 0;
          const revert = dragLevel > 3 ? true : false;
          sortCompInCard(parentComp, index, revert);
        }
      } else {
        if (dragLevel <= 3) {
          parentComp?.children.default?.splice(
            info.dropPosition,
            0,
            currComp.id
          );
        } else {
          const len = parentComp?.children.default.length;
          parentComp?.children.default?.splice(
            len - info.dropPosition,
            0,
            currComp.id
          );
        }

        if (currParent?.id != parentComp.id) {
          const revert = dragLevel > 3 ? true : false;
          const len = parentComp?.children.default.length - 1;
          const index = revert ? len - info.dropPosition : info.dropPosition;
          sortCompInCard(parentComp, index, revert);
        }
      }
      nextTick(() => {
        controls.editorCtrl.clickPickComp(currComp.id);
        helper.extendStreamCard(parentComp.id);
      });
    };
    const sortCompInCard = (
      parentComp: DesignComp,
      index: number,
      revert = false
    ) => {
      if (parentComp?.compKey != "Container") {
        return;
      }
      const children = parentComp.children.default || [];
      if (children?.length > 0) {
        const prveCompId = revert ? children[index + 1] : children[index - 1];
        const nowCompId = children[index];
        const nowComp = helper.findComp(nowCompId);
        if (!prveCompId) {
          const nowCompBound = helper.getCardCompBound(nowCompId);
          if (!nowComp) {
            return;
          }
          const nowObj = new CompObject(nowComp);
          nowObj.worldTransform.translate(-nowCompBound.x, -nowCompBound.y);
          nowComp.layout.transformMatrix = nowObj.worldTransform.getMatrixStr();
          return;
        }
        const prevCompBound = helper.getCardCompBound(prveCompId);
        const prevComp = helper.findComp(prveCompId);
        if (!prevComp || !nowComp) {
          return;
        }
        const obj = new CompObject(prevComp);
        const yOffset = prevCompBound.h;
        obj.worldTransform.translate(0, yOffset);
        nowComp.layout.transformMatrix = obj.worldTransform.getMatrixStr();
      }
    };

    return () => (
      <div class="!overflow-x-auto">
        <Tree
          class={treeStyle}
          treeData={state.treeData}
          v-model={[state.expandedKeys, "expandedKeys"]}
          selectedKeys={[store.currCompId]}
          blockNode={true}
          draggable={true}
          onDrop={onDrop}
          onSelect={(ids) => {
            const id =
              (ids[0] as string) || state.expandedKeys.at(-2) || "root";
            controls.editorCtrl.clickPickComp(id);
          }}
        >
          {{
            title: (data: any) => {
              return <CompNode title={data.title} id={data.key} />;
            },
          }}
        </Tree>
      </div>
    );
  },
});

const CompNode = defineComponent({
  props: {
    id: string().isRequired,
    title: string().isRequired,
  },
  setup(props) {
    const editor = useEditor();
    const comp = editor.helper.findComp(props.id);
    const textTitle = (value: any) => {
      const reg = /<[^>]+>/gi;
      const text = value.text.replace(reg, "");
      return text.substring(0, 10);
    };
    return () => {
      if (!comp) return;

      const compOpts = editor.controls.compUICtrl.state.components.get(
        comp.compKey
      );
      const actions = TreeToolbars[comp.compKey] || TreeToolbars.default;
      const thumbnail =
        comp.compKey === "Image"
          ? comp.value.url
          : comp.thumbnail || compOpts?.thumbnail;
      const title =
        comp.compKey === "Text" ? textTitle(comp.value) : props.title;

      return (
        <div class={[nodeStyle, "flex"]}>
          <Image src={thumbnail} size={240} />
          <span class="flex-1 w-0 text-12px whitespace-nowrap overflow-hidden overflow-ellipsis pr-6px">
            {title}
          </span>
          <span class="actions space-x-2px whitespace-nowrap transition">
            {actions.map((action, i) => {
              return action.getVisible.call(editor, comp) ? (
                <action.component
                  key={i}
                  class={["p-4px", action.getValue?.(comp) ? "active" : ""]}
                  value={action.getValue?.(comp)}
                  onClick={(e: MouseEvent) => {
                    e.stopPropagation();
                    action.onClick.call(editor, comp);
                  }}
                />
              ) : null;
            })}
          </span>
        </div>
      );
    };
  },
});

const treeStyle = css`
  .ant-tree-switcher {
    display: flex;
    width: 14px;
    padding-right: 4px;
    justify-content: center;
    align-items: center;
  }
  .ant-tree-indent-unit {
    width: 4px;
  }
`;

const nodeStyle = css`
  display: flex;
  align-items: center;
  padding: 6px 2px;
  @apply rounded;

  > img {
    width: 20px;
    height: 20px;
    margin-right: 4px;
    object-fit: contain;
  }
  .actions {
    .inficon {
      opacity: 0;
      font-size: 14px;
      &.active {
        opacity: 1;
      }
    }
  }
  &:hover {
    .actions {
      .inficon {
        opacity: 1;
      }
    }
  }
`;
