/**
 * Uniapp DOM 事件桥接类，用于将 DOM 事件桥接到 EventBus
 * 支持将 DOM 事件转换为 EventBus 事件，可配置是否阻止默认行为和停止传播
 * 
 * @author ZFSun <lauer3912@gmail.com>
 * @version 1.0.0
 * @createTime 2023-08-10
 */

class DomEventBridge {
    constructor() {
        this.eventBus = null
        this.domListeners = new Map()
    }

    // 设置 EventBus 实例
    setEventBus(eventBus) {
        this.eventBus = eventBus
    }

    // 桥接 DOM 事件到 EventBus
    bridgeDomEvent(domEventName, eventBusEventName, options = {}) {
        const handler = (domEvent) => {
            if (!this.eventBus) return

            // 创建 EventBus 兼容的事件对象
            const eventBusEvent = this.createEventBusEvent(domEvent, eventBusEventName)

            // 触发 EventBus 事件
            const shouldContinue = this.eventBus.emit(eventBusEventName, eventBusEvent)

            // 根据 EventBus 处理结果决定是否阻止 DOM 事件默认行为
            if (!shouldContinue && options.preventDefault) {
                domEvent.preventDefault()
            }

            // 根据 EventBus 处理结果决定是否停止 DOM 事件传播
            if (!shouldContinue && options.stopPropagation) {
                domEvent.stopPropagation()
            }
        }

        // 保存监听器引用以便清理
        const listenerKey = `${domEventName}-${eventBusEventName}`
        this.domListeners.set(listenerKey, handler)

        // 添加 DOM 事件监听
        // #ifdef H5
        document.addEventListener(domEventName, handler, options)
        // #endif

        return () => this.unbridgeDomEvent(domEventName, eventBusEventName)
    }

    // 创建 EventBus 兼容的事件对象
    createEventBusEvent(domEvent, eventBusEventName) {
        return {
            type: eventBusEventName,
            domEvent: domEvent,
            originalEvent: domEvent,
            target: domEvent.target,
            currentTarget: domEvent.currentTarget,
            timestamp: Date.now(),

            // EventBus 的取消方法
            preventDefault: function () {
                this._preventDefault = true
            },

            stopPropagation: function () {
                this._stopPropagation = true
            },

            // DOM 事件的代理方法
            stopImmediatePropagation: function () {
                domEvent.stopImmediatePropagation()
            },

            get isDefaultPrevented() {
                return this._preventDefault || false
            },

            get isPropagationStopped() {
                return this._stopPropagation || false
            }
        }
    }

    // 取消桥接
    unbridgeDomEvent(domEventName, eventBusEventName) {
        const listenerKey = `${domEventName}-${eventBusEventName}`
        const handler = this.domListeners.get(listenerKey)

        if (handler) {
            // #ifdef H5
            document.removeEventListener(domEventName, handler)
            // #endif
            this.domListeners.delete(listenerKey)
        }
    }

    // 从 EventBus 触发 DOM 事件
    triggerDomEventFromEventBus(domEventName, detail = {}) {
        // #ifdef H5
        const event = new CustomEvent(domEventName, {
            bubbles: true,
            cancelable: true,
            detail: detail
        })

        document.dispatchEvent(event)
        return !event.defaultPrevented
        // #endif

        // #ifdef MP
        // 小程序环境不支持 DOM 事件
        return true
        // #endif
    }

    // 清理所有桥接
    destroy() {
        for (const [listenerKey, handler] of this.domListeners) {
            const [domEventName] = listenerKey.split('-')
            // #ifdef H5
            document.removeEventListener(domEventName, handler)
            // #endif
        }
        this.domListeners.clear()
    }
}

export default new DomEventBridge()