import { defineAsyncComponent, Component } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useRouterStore } from '@/stores'
import { AuthType } from '@/constants/menu'

export function useMenu(authCode?: string) {
    const menuStore = useRouterStore()
    const { userRoutes } = menuStore.$toRefs()

    const route = useRoute()
    const router = useRouter()
    const componentMap = new Map<string, Component>()

    // 过滤菜单
    const filterMenu = (data: Model.MenusRsp[], parentPath = '') => {
        const result: Model.MenusRsp[] = []
        data.forEach((e) => {
            if (e.show && e.authType === AuthType.Menu) {
                const routePath = (parentPath ? parentPath + '/' : '') + e.url
                result.push({
                    ...e,
                    url: routePath,
                    children: e.children ? filterMenu(e.children, routePath) : [],
                })
            }
        })
        return result
    }

    /**
     * 根据 code 查找对应的子菜单
     * @returns 
     */
    const findChildren = (data: Model.MenusRsp[], code?: string): Model.MenusRsp[] => {
        const routeName = code ?? route.name?.toString()
        for (const item of data) {
            const { resourceCode, children } = item
            if (resourceCode === routeName) return children ?? []
            if (children) {
                const res = findChildren(children, routeName)
                if (res.length) return res
            }
        }
        return []
    }

    /**
     * 获取路由菜单(无限级)
     * @param level 
     * @returns 
     */
    const getMenus = (level = 0) => {
        // 过滤层级
        const filterLevel = (data: Model.MenusRsp[], n: number): Model.MenusRsp[] => {
            if (level) {
                return data.map((e) => ({ ...e, children: n <= 1 ? [] : filterLevel(e.children ?? [], n - 1) }))
            }
            return data
        }
        return filterMenu(filterLevel(userRoutes.value, level))
    }

    /**
    * 获取路由子菜单
    * @param code 
    * @returns 
    */
    const getChildrenMenus = (code?: string) => {
        const children = findChildren(userRoutes.value, code)
        return filterMenu(children)
    }

    /**
     * 获取操作权限
     * @returns 
     */
    const getAuth = (authType: AuthType) => {
        const children = findChildren(userRoutes.value, authCode)
        return children.reduce((res, cur) => {
            if (cur.show && cur.authType === authType) {
                if (!componentMap.get(cur.resourceCode) && cur.component) {
                    const componentString = cur.component.replace(/^\/+/, '') // 过滤字符串前面所有 '/' 字符
                    const componentPath = componentString.replace(/\.\w+$/, '') // 过滤后缀名，为了让 import 加入 .vue ，不然会有警告提示...
                    const asyncComponent = defineAsyncComponent({
                        loader: () => import('/' + process.env.VUE_APP_ROOT + componentPath + '.vue'),
                    })
                    componentMap.set(cur.resourceCode, asyncComponent)
                }
                res.push(JSON.parse(JSON.stringify(cur)))
            }
            return res
        }, [] as Model.MenusRsp[])
    }

    /**
     * 过滤操作权限
     * @param filtered 过滤的数据项
     * @param reverse 是否反向过滤
     * @returns 
     */
    const authFilter = (authType: AuthType, filtered: string[], reverse: boolean) => {
        const auth = getAuth(authType);
        if (filtered.length) {
            if (reverse) {
                // 返回除指定的权限代码
                return auth.filter((e) => !filtered.includes(e.resourceCode))
            } else {
                // 返回指定的权限代码
                return auth.filter((e) => filtered.includes(e.resourceCode))
            }
        }
        return auth
    }

    /**
     * 获取权限按钮
     * @param filtered 
     * @param reverse 
     * @returns 
     */
    const getAuthButtons = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Operate, filtered, reverse)

    /**
     * 获取权限组件
     * @param filtered 
     * @param reverse 
     * @returns 
     */
    const getAuthComponents = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Component, filtered, reverse)

    return {
        route,
        router,
        userRoutes,
        componentMap,
        getMenus,
        getChildrenMenus,
        getAuthButtons,
        getAuthComponents,
    }
}