import { computed, ref, watch } from "vue";
import { useRouter } from "vue-router";
import { defineStore } from "pinia";
import { getRolesByRoleId } from "@/api/corp";
import { getMenuList } from "@/api/system.js";

export const tagsStore = defineStore("tags", () => {
  const router = useRouter();
  const FixedTags = ["WORK"];
  const menuTree = ref([]);
  const menus = ref([]);
  const fixedTags = computed(() => {
    return FixedTags.map((name) => {
      const menu = menus.value.find((i) => i.path === name);
      const route = menu ? router.resolve({ name }) : null;
      return route
        ? {
            name: menu.customMenuName || menu.menuName || route.meta.title,
            routeName: route.name,
            path: route.fullPath,
            multTag: Boolean(route.meta.multTag),
            type: "fixed",
          }
        : null;
    }).filter(Boolean);
  });

  const tags = ref([]);
  const selectTag = ref("");
  const triggle = new Map();
  const allTags = computed(() => [...fixedTags.value, ...tags.value]);

  function addTag(tag) {
    selectTag.value = tag.path;
    if (allTags.value.some((i) => i.path === tag.path)) return;

    const item = { ...tag };
    const menu = menus.value.find((i) => i.path === item.routeName);
    if (menu) {
      item.name = menu.customMenuName || menu.menuName;
    }
    const index = tags.value.findIndex((i) => i.routeName === tag.routeName);
    if (index >= 0 && !tag.multTag) {
      tags.value.splice(index, 1, item);
      return;
    }
    const preIndex = tags.value.findIndex((i) => item.prePath && i.path === item.prePath);
    if (preIndex >= 0) {
      tags.value.splice(preIndex + 1, 0, item);
    } else {
      tags.value.push(item);
    }
  }

  function changeTag(tag) {
    selectTag.value = tag.path;
  }

  function closeTag(tag) {
    broadcast(tag.path);
    if (tag.path === selectTag.value) {
      const preTag = allTags.value.find((i) => tag.prePath && i.path === tag.prePath);
      const index = allTags.value.findIndex((i) => i.path === selectTag.value);
      const targetTag = preTag || allTags.value[index + 1] || allTags.value[index - 1];
      selectTag.value = targetTag ? targetTag.path : "";
      if (targetTag) router.push({ path: targetTag.path });
    }
    tags.value = tags.value.filter((i) => i.path !== tag.path);
  }

  function renameTag(path, name) {
    const tag = tags.value.find((i) => i.path === path);
    if (tag) tag.showName = name;
  }

  function removeTag(path) {
    const index = tags.value.findIndex((i) => i.path === path);
    if (index >= 0) closeTag(tags.value[index]);
  }

  function subTagClosed(path, fn) {
    const callbacks = triggle.get(path) || [];
    callbacks.push(fn);
    triggle.set(path, callbacks);
  }

  function unsubTagClosed(path) {
    triggle.delete(path);
  }

  function broadcast(path) {
    const callbacks = triggle.get(path);
    if (Array.isArray(callbacks) && callbacks.length) {
      callbacks.forEach((fn) => typeof fn === "function" && fn());
      triggle.delete(path);
    }
  }

  function getTagState(path = selectTag.value) {
    const tag = allTags.value.find((i) => i.path === path);
    return tag && tag.state ? tag.state : {};
  }

  function setTagState(data = {}, path = selectTag.value) {
    const tag = allTags.value.find((i) => i.path === path);
    if (tag) tag.state = data;
  }

  function setMenus(list) {
    menus.value = list;
    return menus.value;
  }

  function setCustomMenuName(menuId, name) {
    const index = menus.value.findIndex((i) => i.menuId === menuId);
    if (index >= 0) {
      const list = menus.value.map((i) => {
        const menu = { ...i };
        if (i.menuId === menuId) menu.customMenuName = name;
        return menu;
      });
      setMenus(list);
    }
  }

  function clear() {
    tags.value = [];
    triggle.clear();
    selectTag.value = "";
  }

  async function setUserMenus(roleIds) {
    if (!Array.isArray(roleIds)) {
      throw new Error("获取账号角色信息失败，请联系管理员");
    }
    const { success, data } = await getRolesByRoleId(roleIds);
    if (!success) {
      throw new Error("获取账号角色信息失败，请联系管理员");
    }
    const roles = data && Array.isArray(data.data) ? data.data : [];
    if (roles.length === 0) {
      throw new Error("获取账号角色信息失败，请联系管理员");
    }
    const menuIds = roles.reduce((list, item) => {
      if (Array.isArray(item.menuList)) {
        list.push(...item.menuList);
      }
      return list;
    }, []);
    const ids = Array.from(new Set(menuIds));
    if (ids.length === 0) {
      throw new Error("管理员未配置角色菜单信息，请联系管理员");
    }
    const res = await getMenuList(ids);
    if (!res.success) {
      throw new Error("获取菜单信息失败");
    }
    const menusData = res.data && Array.isArray(res.data.data) ? res.data.data : [];
    if (menusData.length === 0) {
      throw new Error("管理员未配置角色菜单信息，请联系管理员");
    }
    setMenus(menusData);
    menuTree.value = getMenuTree(menusData);
    return menuTree.value;
  }

  watch(
    menus,
    () => {
      tags.value.forEach((tag) => {
        const menu = menus.value.find((i) => i.path === tag.routeName);
        if (menu) tag.name = menu.customMenuName || menu.menuName;
      });
    },
    { immediate: true }
  );

  return {
    tags: allTags,
    selectTag,
    addTag,
    changeTag,
    closeTag,
    renameTag,
    removeTag,
    subTagClosed,
    unsubTagClosed,
    getTagState,
    setTagState,
    menus,
    setMenus,
    setCustomMenuName,
    clear,
    setUserMenus,
    menuTree,
  };
});

function getMenuTree(menus) {
  const map = menus.reduce((val, menu) => ((val[menu.menuId] = menu), val), {});
  const relationships = {};
  menus.forEach((item) => {
    const { parentId, menuId } = item;
    if (!relationships[parentId]) relationships[parentId] = [];
    relationships[parentId].push(menuId);
  });

  const buildTree = (parentId) => {
    const children = relationships[parentId];
    if (!children) return null;
    return children
      .map((child) => ({
        ...(map[child] || {}),
        parentId,
        menuId: child,
        children: buildTree(child),
      }))
      .sort((a, b) => a.sort - b.sort);
  };

  const roots = relationships[0] || [];
  return roots
    .map((root) => ({
      ...(map[root] || {}),
      parentId: 0,
      isGroup: !("path" in (map[root] || {})),
      menuId: root,
      children: buildTree(root) || [],
    }))
    .sort((a, b) => a.sort - b.sort);
}
