import { ref, Ref, onUnmounted } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
import { v4 } from 'uuid'

// 缓存已打开的组件实例
const componentInstanceMap = new Map<string, Ref>()

/**
 * @param callback 组件关闭时的回调
 * @returns 
 */
export function useComponent(callback?: (componentName?: string) => void) {
    const uuid = v4()
    const components = new Set<string>() // 已打开的组件列表
    const componentId = ref<string>() // 当前显示的组件
    const componentRef = ref() // 组件实例

    // 添加到组件实例
    componentInstanceMap.set(uuid, componentRef)

    /**
     * 是否存在组件
     * @returns 
     */
    const hasComponent = () => {
        return components.size > 0
    }

    /**
     * 打开组件
     * @param componentName 
     */
    const openComponent = (componentName: string) => {
        components.add(componentName)
        componentId.value = componentName
    }

    /**
     * 关闭组件
     * @param isCallback 
     */
    const closeComponent = (isCallback?: boolean) => {
        const componentName = componentId.value
        if (componentName) {
            components.delete(componentName)
            componentId.value = [...components.values()].pop()

            // 是否刷新数据
            if (isCallback && callback) {
                callback(componentName)
            }
        }
    }

    /**
     * 组件关闭守卫
     * @returns 
     */
    const closeComponentEach = () => {
        if (hasComponent()) {
            const mapValues = [...componentInstanceMap.values()]
            // 倒序关闭已打开的组件
            for (let i = mapValues.length - 1; i >= 0; i--) {
                const componentInstance = mapValues[i].value
                if (componentInstance) {
                    const { closed } = componentInstance ?? {}
                    if (closed instanceof Function) {
                        closed()
                        return false
                    }
                }
            }
            closeComponent()
            return false
        }
        return true
    }

    /**
     * 路由守卫，离开页面前关闭组件
     */
    onBeforeRouteLeave((to, from, next) => {
        if (closeComponentEach()) {
            next()
        } else {
            next(false)
        }
    })

    onUnmounted(() => {
        componentInstanceMap.delete(uuid)
    })

    return {
        componentId,
        componentRef,
        hasComponent,
        openComponent,
        closeComponent,
        closeComponentEach,
    }
}