import { workletUnRef } from './workletRef.js';
import { RefProxy } from '../lifecycle/ref/delay.js';
const refsToClear = [];
const refsToApply = [];
function unref(snapshot, recursive) {
    snapshot.__worklet_ref_set?.forEach(v => {
        if (v) {
            workletUnRef(v);
        }
    });
    snapshot.__worklet_ref_set?.clear();
    if (recursive) {
        snapshot.childNodes.forEach(it => {
            unref(it, recursive);
        });
    }
}
// This function is modified from preact source code.
function applyRef(ref, value) {
    const newRef = value && new RefProxy(value);
    try {
        if (typeof ref == 'function') {
            const hasRefUnmount = typeof ref._unmount == 'function';
            if (hasRefUnmount) {
                ref._unmount();
            }
            if (!hasRefUnmount || newRef != null) {
                // Store the cleanup function on the function
                // instance object itself to avoid shape
                // transitioning vnode
                ref._unmount = ref(newRef);
            }
        }
        else
            ref.current = newRef;
        /* v8 ignore start */
    }
    catch (e) {
        lynx.reportError(e);
    }
    /* v8 ignore stop */
}
function updateRef(snapshot, expIndex, oldValue, elementIndex) {
    const value = snapshot.__values[expIndex];
    let ref;
    if (typeof value === 'string') {
        ref = value;
    }
    else {
        ref = `react-ref-${snapshot.__id}-${expIndex}`;
    }
    snapshot.__values[expIndex] = ref;
    if (snapshot.__elements && oldValue !== ref) {
        if (oldValue) {
            __SetAttribute(snapshot.__elements[elementIndex], oldValue, undefined);
        }
        if (ref) {
            __SetAttribute(snapshot.__elements[elementIndex], ref, 1);
        }
    }
}
function getRefFromValue(val) {
    if (!val || (typeof val !== 'object' && typeof val !== 'function')) {
        return null;
    }
    if ('__spread' in val && 'ref' in val) {
        return (val.ref) ?? null;
    }
    if ('__ref' in val) {
        return val;
    }
    return null;
}
function transformRef(ref) {
    if (ref === undefined || ref === null) {
        return ref;
    }
    if (typeof ref === 'function' || (typeof ref === 'object' && 'current' in ref)) {
        if ('__ref' in ref) {
            return ref;
        }
        return Object.defineProperty(ref, '__ref', { value: 1 });
    }
    throw new Error(`Elements' "ref" property should be a function, or an object created `
        + `by createRef(), but got [${typeof ref}] instead`);
}
function applyQueuedRefs() {
    try {
        for (const ref of refsToClear) {
            applyRef(ref, null);
        }
        for (let i = 0; i < refsToApply.length; i += 2) {
            const ref = refsToApply[i];
            const value = refsToApply[i + 1];
            applyRef(ref, value);
        }
    }
    finally {
        clearQueuedRefs();
    }
}
function queueRefAttrUpdate(oldRef, newRef, snapshotInstanceId, expIndex) {
    if (oldRef === newRef) {
        return;
    }
    if (oldRef) {
        refsToClear.push(oldRef);
    }
    if (newRef) {
        refsToApply.push(newRef, [snapshotInstanceId, expIndex]);
    }
}
function clearQueuedRefs() {
    refsToClear.length = 0;
    refsToApply.length = 0;
}
/**
 * @internal
 */
export { queueRefAttrUpdate, updateRef, unref, transformRef, applyRef, applyQueuedRefs, clearQueuedRefs, getRefFromValue, };
//# sourceMappingURL=ref.js.map