import { isBoolean } from 'lodash-es'
import { isProdMode } from '@/utils/env'

export interface BasicWidgetProps {
    // 是否显示
    show?: boolean
}

export interface BasicWidgetInstance<T extends BasicWidgetProps = BasicWidgetProps> {
    /**
     * 设置小部件属性
     * @param props 小部件属性
     */
    setProps: (props: Partial<T>) => void
    /**
     * 切换显示状态
     * @param show 是否显示，强制指定显示状态
     */
    toggleShow: (show?: boolean) => void
}

/**
 * 获取 Boolean 值或默认值
 * @param value Boolean 值
 * @param def 默认值
 * @returns 值或默认值
 */
export function getBooleanOrDefault(value: any, def = null): boolean {
    return isBoolean(value) ? value : def
}

/**
 * 注册组件工厂
 * @param instanceRef 组件实例 Ref
 * @param props 组件属性
 * @param callback 回调函数
 */
export function registerWidgetFactory<T extends BasicWidgetInstance<P>, P>(
    instanceRef: Ref<Nullable<T>>,
    props: P,
    callback?: (instance: T) => void,
): (instance: T) => void {
    function register(instance: T) {
        if (isProdMode()) {
            if (instance === unref(instanceRef)) {
                return
            }

            onUnmounted(() => {
                instanceRef.value = null
            })
        }

        instanceRef.value = instance
        props && instance?.setProps(props)
        callback && callback(instance)
    }

    return register
}

/**
 * 获取组件实例
 * @param instanceRef 组件实例 Ref
 * @param name 组件名称
 * @returns 组件实例
 */
export function getWidgetInstance<T extends BasicWidgetInstance>(instanceRef: Ref<Nullable<T>>, name?: string): T {
    const instance = unref(instanceRef)
    if (!instance) {
        console.warn(`The ${name || 'widget'} instance has not been obtained`)
    }
    return instance as T
}

/**
 * 获取基础组件实例函数
 * @param instanceRef 组件实例 Ref
 * @param name 组件名称
 * @returns 组件实例函数
 * @example
 * ```ts
 * const { get, setProps, toggleShow } = unpackWidgetInstance<BasicWidgetInstance, BasicWidgetProps>(instanceRef, 'basic widget')
 * ```
 */
export function unpackWidgetInstance<T extends BasicWidgetInstance, P extends BasicWidgetProps>(
    instanceRef: Ref<Nullable<T>>,
    name?: string,
) {
    const get = () => getWidgetInstance(instanceRef, name)

    return {
        get,
        setProps: (props: Partial<P>) => get()?.setProps(props),
        toggleShow: (show?: boolean) => get()?.toggleShow(getBooleanOrDefault(show)),
    } as T & { get: () => T }
}
