import { createCrossThreadEvent } from './createCrossThreadEvent.js';
import { LynxEventNameToW3cCommon, uniqueIdSymbol, } from '../../../constants.js';
import { __GetElementUniqueID } from './pureElementPAPIs.js';
export class WASMJSBinding {
    lynxViewInstance;
    wasmContext;
    disposeWasmContext;
    #addedEventListeners = new Set();
    toBeEnabledElement = new Set();
    toBeDisabledElement = new Set();
    constructor(lynxViewInstance) {
        this.lynxViewInstance = lynxViewInstance;
    }
    markExposureRelatedElementByUniqueId(element, toEnable) {
        if (element) {
            if (toEnable) {
                this.toBeDisabledElement.delete(element);
                this.toBeEnabledElement.add(element);
            }
            else {
                this.toBeEnabledElement.delete(element);
                this.toBeDisabledElement.add(element);
            }
        }
    }
    generateTargetObject(element, dataset) {
        const uniqueId = element[uniqueIdSymbol];
        return {
            dataset: Object.assign(Object.create(null), dataset),
            id: element.id || null,
            uid: uniqueId,
        };
    }
    getClassList(elementRef) {
        const element = elementRef.deref();
        if (element) {
            return [...element.classList];
        }
        return [];
    }
    getElementByUniqueId(uniqueId) {
        return this.wasmContext?.get_dom_by_unique_id(uniqueId)?.deref();
    }
    getElementByComponentId(componentId) {
        const uniqueId = this.wasmContext?.get_unique_id_by_component_id(componentId);
        if (uniqueId != undefined) {
            return this.getElementByUniqueId(uniqueId);
        }
        return undefined;
    }
    runWorklet(handler, eventObject, targetUniqueId, targetDataset, currentTargetUniqueId, currentTargetDataset) {
        const target = this.getElementByUniqueId(targetUniqueId);
        const currentTarget = this.getElementByUniqueId(currentTargetUniqueId);
        eventObject.target = this.generateTargetObject(target, targetDataset);
        eventObject.currentTarget = this.generateTargetObject(currentTarget, currentTargetDataset);
        // @ts-expect-error
        eventObject.target.elementRefptr = target;
        // @ts-expect-error
        eventObject.currentTarget.elementRefptr = currentTarget;
        this.lynxViewInstance.mainThreadGlobalThis.runWorklet?.(handler.value, [
            eventObject,
        ]);
    }
    publishEvent(handlerName, parentComponentId, eventObject, targetUniqueId, targetDataset, currentTargetUniqueId, currentTargetDataset) {
        const target = this.getElementByUniqueId(targetUniqueId);
        const currentTarget = this.getElementByUniqueId(currentTargetUniqueId);
        eventObject.target = this.generateTargetObject(target, targetDataset);
        eventObject.currentTarget = this.generateTargetObject(currentTarget, currentTargetDataset);
        if (parentComponentId) {
            this.lynxViewInstance?.backgroundThread.publicComponentEvent(parentComponentId, handlerName, eventObject);
        }
        else {
            this.lynxViewInstance.backgroundThread.publishEvent(handlerName, eventObject);
        }
    }
    #commonEventHandler = (event) => {
        const target = event.target;
        let bubblePath = new Uint32Array(32);
        let bubblePathLength = 0;
        bubblePath;
        let currentTarget = target;
        while (currentTarget) {
            if (currentTarget === this.lynxViewInstance.rootDom) {
                break;
            }
            const uniqueId = __GetElementUniqueID(currentTarget);
            if (uniqueId !== -1) {
                bubblePath[bubblePathLength++] = uniqueId;
                if (bubblePathLength >= bubblePath.length) {
                    const newBubblePath = new Uint32Array(bubblePath.length * 2);
                    newBubblePath.set(bubblePath);
                    bubblePath = newBubblePath;
                }
            }
            currentTarget = currentTarget.parentElement;
        }
        const eventObject = createCrossThreadEvent(event);
        this.wasmContext?.common_event_handler(eventObject, bubblePath.slice(0, bubblePathLength), eventObject.type, event.bubbles);
    };
    addEventListener(eventName) {
        const w3cEventName = LynxEventNameToW3cCommon[eventName] ?? eventName;
        if (this.#addedEventListeners.has(w3cEventName))
            return;
        this.#addedEventListeners.add(w3cEventName);
        this.lynxViewInstance.rootDom.addEventListener(w3cEventName, this.#commonEventHandler, {
            passive: true,
            capture: true,
        });
    }
    dispose() {
        for (const eventName of this.#addedEventListeners) {
            this.lynxViewInstance.rootDom.removeEventListener(eventName, this.#commonEventHandler, true);
        }
        this.#addedEventListeners.clear();
        this.toBeEnabledElement.clear();
        this.toBeDisabledElement.clear();
        this.disposeWasmContext?.();
        this.wasmContext = undefined;
    }
    postTimingFlags(flags, pipelineId) {
        this.lynxViewInstance.backgroundThread.postTimingFlags(flags, pipelineId);
    }
    updateExposureStatus(enabledExposureElements, disabledExposureElements) {
        this.lynxViewInstance.exposureServices.updateExposureStatus(enabledExposureElements, disabledExposureElements);
    }
    enableElementEvent(elementRef, eventName) {
        const element = elementRef.deref();
        if (element) {
            // @ts-expect-error
            element.enableEvent?.(LynxEventNameToW3cCommon[eventName] ?? eventName);
        }
    }
    disableElementEvent(elementRef, eventName) {
        const element = elementRef.deref();
        if (element) {
            // @ts-expect-error
            element.disableEvent?.(LynxEventNameToW3cCommon[eventName] ?? eventName);
        }
    }
    setAttribute(elementRef, name, value) {
        const element = elementRef.deref();
        if (element) {
            element.setAttribute(name, value);
        }
    }
    removeAttribute(elementRef, name) {
        const element = elementRef.deref();
        if (element) {
            element.removeAttribute(name);
        }
    }
}
//# sourceMappingURL=WASMJSBinding.js.map