import { defineStore } from 'pinia'
import { isExternal } from '@/utils/validate'
import type {
    LocationQuery,
    RouteLocationNormalized,
    RouteParamsRaw,
    Router,
    RouteRecordName
} from 'vue-router'
import { PageEnum } from '@/enums/pageEnum'

interface TabItem {
    name: RouteRecordName
    fullPath: string
    path: string
    title?: string
    query?: LocationQuery
    params?: RouteParamsRaw
}

interface TabsSate {
    cacheTabList: Set<string>
    tabList: TabItem[]
    tasMap: Record<string, TabItem>
    indexRouteName: RouteRecordName
}

const getHasTabIndex = (fullPath: string, tabList: TabItem[]) => {
    return tabList.findIndex((item) => item.fullPath == fullPath)
}

const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
    const { path, meta, name } = route
    if (!path || isExternal(path)) return true
    if (meta?.hideTab) return true
    if (!router.hasRoute(name!)) return true
    if (([PageEnum.LOGIN, PageEnum.ERROR_403] as string[]).includes(path)) {
        return true
    }
    return false
}

const findTabsIndex = (fullPath: string, tabList: TabItem[]) => {
    return tabList.findIndex((item) => item.fullPath === fullPath)
}

const getComponentName = (route: RouteLocationNormalized) => {
    return route.matched.at(-1)?.components?.default?.name
}

export const getRouteParams = (tabItem: TabItem) => {
    const { params, path, query } = tabItem
    return {
        params: params || {},
        path,
        query: query || {}
    }
}

const useTabsStore = defineStore({
    id: 'tabs',
    state: (): TabsSate => ({
        cacheTabList: new Set(),
        tabList: [],
        tasMap: {},
        indexRouteName: ''
    }),
    getters: {
        getTabList(): TabItem[] {
            return this.tabList
        },
        getCacheTabList(): string[] {
            return Array.from(this.cacheTabList)
        }
    },
    actions: {
        setRouteName(name: RouteRecordName) {
            this.indexRouteName = name
        },
        addCache(componentName?: string) {
            if (componentName) this.cacheTabList.add(componentName)
        },
        removeCache(componentName?: string) {
            if (componentName && this.cacheTabList.has(componentName)) {
                this.cacheTabList.delete(componentName)
            }
        },
        clearCache() {
            this.cacheTabList.clear()
        },
        resetState() {
            this.cacheTabList = new Set()
            this.tabList = []
            this.tasMap = {}
            this.indexRouteName = ''
        },
        addTab(router: Router) {
            const route = unref(router.currentRoute)
            const { name, query, meta, params, fullPath, path } = route
            if (isCannotAddRoute(route, router)) return
            const hasTabIndex = getHasTabIndex(fullPath!, this.tabList)
            const componentName = getComponentName(route)
            const tabItem = {
                name: name!,
                path,
                fullPath,
                title: meta?.title,
                query,
                params
            }
            this.tasMap[fullPath] = tabItem
            if (meta?.keepAlive) {
                this.addCache(componentName)
            }
            if (hasTabIndex != -1) {
                return
            }

            this.tabList.push(tabItem)
        },
        removeTab(fullPath: string, router: Router) {
            const { currentRoute, push } = router
            const index = findTabsIndex(fullPath, this.tabList)
            // 移除tab
            if (this.tabList.length > 1) {
                index !== -1 && this.tabList.splice(index, 1)
            }
            const componentName = getComponentName(currentRoute.value)
            this.removeCache(componentName)
            if (fullPath !== currentRoute.value.fullPath) {
                return
            }
            // 删除选中的tab
            let toTab: TabItem | null = null

            if (index === 0) {
                toTab = this.tabList[index]
            } else {
                toTab = this.tabList[index - 1]
            }

            const toRoute = getRouteParams(toTab)
            push(toRoute)
        },
        removeOtherTab(route: RouteLocationNormalized) {
            this.tabList = this.tabList.filter((item) => item.fullPath == route.fullPath)
            const componentName = getComponentName(route)
            this.cacheTabList.forEach((name) => {
                if (componentName !== name) {
                    this.removeCache(name)
                }
            })
        },
        removeAllTab(router: Router) {
            const { push, currentRoute } = router
            const { name } = unref(currentRoute)
            if (name == this.indexRouteName) {
                this.removeOtherTab(currentRoute.value)
                return
            }
            this.tabList = []
            this.clearCache()
            push(PageEnum.INDEX)
        }
    }
})

export default useTabsStore