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";

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();

        function getCompChildren(ids: string[]): TreeItem[] {
          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: 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 = null;
      if (dragLevel > dropLevel) {
        parentComp = helper.findComp(dropKey);
      } else {
        parentComp = helper.findParentComp(dropKey);
      }
      const currComp = helper.findComp(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);
      }
      if (!info.dropToGap) {
        parentComp?.children.default == parentComp?.children.default || [];
        parentComp?.children.default?.unshift(currComp?.id);
      } else {
        parentComp?.children.default?.splice(info.dropPosition, 0, currComp.id);
      }
    };

    return () => (
      <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";
          actions.pickComp(id);
        }}
      >
        {{
          title: (data: any) => {
            return <CompNode title={data.title} id={data.key} />;
          },
        }}
      </Tree>
    );
  },
});

const CompNode = defineComponent({
  props: {
    id: string().isRequired,
    title: string().isRequired,
  },
  setup(props) {
    const editor = useEditor();
    const comp = editor.helper.findComp(props.id);
    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;
      return (
        <div class={nodeStyle}>
          <Image src={thumbnail} size={240} />
          <span class="w-0 flex-1 truncate">{props.title}</span>
          <span class="space-x-4px">
            {actions.map((action, i) =>
              action.getVisible.call(editor, comp) ? (
                <action.component
                  key={i}
                  class="p-4px"
                  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;
    justify-content: center;
    align-items: center;
  }
`;

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

  > img {
    width: 24px;
    height: 24px;
    margin-right: 6px;
    object-fit: contain;
  }
`;
