import { defineStore } from 'pinia'
import router from '@/router'
import useFetch from '@/hooks/useFetch'

import type { RouteRecordRaw } from 'vue-router'
import type { ExtractApiResponse } from '@/api/api'

export function getMenuRotes() {
  function getMenuInfo(route: RouteRecordRaw): MainLayoutStore.MenuItem {
    return {
      path: route.path,
      menu: route.meta?.menu,
      index: route.meta?.menuId || '',
      icon: route.meta?.icon || '',
      label: route.meta?.label || '',
      sort: route.meta?.sort || 9999,
    }
  }

  type RecordMenu = Record<string, RecordMenuItem>
  type RecordMenuItem = MainLayoutStore.MenuItem & { children: RecordMenu }

  type MenuItem = MainLayoutStore.MenuItem & { children: ArrayMenu[] }
  type ArrayMenu = Array<MenuItem>

  const tempRoutes = router.getRoutes()

  const routesMap = tempRoutes
    .map((_, i) => _.meta?.menuId + '-' + i)
    .filter((_) => !_.startsWith('undefined'))
    .sort()

  const menuTree = routesMap.reduce((total, cur) => {
    const val = cur.split('-')

    const last = val[val.length - 1]

    const children = val
      .slice(0, -1)
      .map((_) => `['${_}']`)
      .join("['children']")
    const func = new Function(
      'obj',
      'serialize',
      `obj${children} = serialize(this[${last}]);obj${children}['children'] = {}; return obj`
    )

    return func.call(tempRoutes, total, getMenuInfo)
  }, {}) as RecordMenu

  function sortMenus(menus: ArrayMenu) {
    return menus.sort((a, b) => a.sort - b.sort)
  }

  function objChild2Arr(obj: RecordMenu, arr: ArrayMenu = []): ArrayMenu {
    for (const k in obj) {
      const kk = k as keyof typeof obj
      const d = obj[kk] as RecordMenuItem
      if (d.menu) {
        arr.push(
          Object.assign({}, d, {
            children: objChild2Arr(d.children, []),
          }) as unknown as MenuItem
        )
      }
    }
    return sortMenus(arr)
  }

  return objChild2Arr(menuTree, [])
}

function filterPrivilege(
  item: MainLayoutStore.MenuItem,
  privilege: ExtractApiResponse<'getUserPrivilege'>
): MainLayoutStore.MenuItem | undefined {
  if (privilege.some((d) => item.index === d.code)) {
    return {
      ...item,
      children: item.children?.filter((child) => !!filterPrivilege(child, privilege)),
    }
  }
}

const useMainLayoutStore = defineStore<
  'main-layout',
  MainLayoutStore.State,
  any,
  { toggleCollapse: () => void; getRenderMenuList: () => Promise<void> }
>('main-layout', {
  state() {
    return {
      collapse: false,
      menuList: getMenuRotes(),
      renderMenus: [],
    }
  },
  actions: {
    toggleCollapse() {
      this.collapse = !this.collapse
    },
    async getRenderMenuList() {
      try {
        const privilege = await useFetch('getUserPrivilege').fetch()
        this.renderMenus = this.menuList.reduce((menus, menu) => {
          return menus.concat(filterPrivilege(menu, privilege) || [])
        }, [] as MainLayoutStore.MenuItem[])
      } catch (error) {
        console.error(error)
      }
    },
  },
})

export default useMainLayoutStore
