// Copyright 2026 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
/**
 * Implements hooks in main thread.
 * This module is modified from preact/hooks
 *
 * internal-preact/hooks/dist/hooks.mjs
 */
import { options } from 'preact';
import { noop } from '../../utils.js';
import { CHILDREN, COMPONENT, DIFF, DIFFED, HOOK, HOOKS, LIST, MASK, PARENT, PENDING_EFFECTS, RENDER, ROOT, VALUE, VNODE, } from '../renderToOpcodes/constants.js';
let currentIndex;
let currentComponent;
let currentHook;
const oldBeforeDiff = options[DIFF];
const oldBeforeRender = options[RENDER];
const oldAfterDiff = options[DIFFED];
const oldRoot = options[ROOT];
options[DIFF] = function (vnode) {
    currentComponent = null;
    if (oldBeforeDiff)
        oldBeforeDiff(vnode);
};
/* v8 ignore start */
options[ROOT] = function (vnode, parentDom) {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    if (vnode && parentDom[CHILDREN] && parentDom[CHILDREN][MASK]) {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
        vnode[MASK] = parentDom[CHILDREN][MASK];
    }
    if (oldRoot)
        oldRoot(vnode, parentDom);
};
/* v8 ignore stop */
options[RENDER] = function (vnode) {
    if (oldBeforeRender)
        oldBeforeRender(vnode);
    currentComponent = vnode[COMPONENT];
    currentIndex = 0;
};
options[DIFFED] = function (vnode) {
    if (oldAfterDiff)
        oldAfterDiff(vnode);
    currentComponent = null;
};
function getHookState(index, type) {
    if (options[HOOK]) {
        options[HOOK](currentComponent, index, currentHook || type);
    }
    currentHook = 0;
    const hooks = currentComponent[HOOKS] ?? (currentComponent[HOOKS] = {
        [LIST]: [],
        [PENDING_EFFECTS]: [],
    });
    if (index >= hooks[LIST].length) {
        hooks[LIST].push({});
    }
    return hooks[LIST][index];
}
function invokeOrReturn(arg, f) {
    return typeof f == 'function' ? f(arg) : f;
}
function useState(initialState) {
    currentHook = 1;
    return useReducer(noop, initialState);
}
function useReducer(_reducer, initialState, init) {
    const hookState = getHookState(currentIndex++, 2);
    if (!hookState[COMPONENT]) {
        hookState[VALUE] = [
            /* v8 ignore start */
            init ? init(initialState) : invokeOrReturn(undefined, initialState),
            /* v8 ignore stop */
            function (_action) {
                if (__DEV__) {
                    console.error('Cannot update state in main thread!');
                }
            },
        ];
        hookState[COMPONENT] = currentComponent;
    }
    return hookState[VALUE];
}
function useRef(initialValue) {
    currentHook = 5;
    return useMemo(function () {
        return {
            current: initialValue,
        };
    }, []);
}
// used for first screen and need not to cache value by args
function useMemo(factory, _args) {
    const state = getHookState(currentIndex++, 7);
    state[VALUE] = factory();
    return state[VALUE];
}
function useCallback(callback, args) {
    currentHook = 8;
    return useMemo(function () {
        return callback;
    }, args);
}
function useContext(context) {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    const provider = currentComponent.context[context.__c];
    const state = getHookState(currentIndex++, 9);
    state['c'] = context;
    /* v8 ignore start */
    if (!provider)
        return context.__;
    /* v8 ignore stop */
    state[VALUE] = true;
    return provider.props.value;
}
function useDebugValue(value, formatter) {
    if (options.useDebugValue) {
        /* v8 ignore start */
        options.useDebugValue(formatter ? formatter(value) : value);
        /* v8 ignore stop */
    }
}
function useErrorBoundary(cb) {
    const state = getHookState(currentIndex++, 10);
    state[VALUE] = cb;
    return [undefined, noop];
}
function useId() {
    const state = getHookState(currentIndex++, 11);
    if (!state[VALUE]) {
        // Grab either the root node or the nearest async boundary node.
        let root = currentComponent[VNODE];
        while (root !== null && !root[MASK] && root[PARENT] !== null) {
            root = root[PARENT];
        }
        /**
         * init mask to [0, 0]
         * mask[0] will not change
         * mask[1] will auto increase
         */
        const mask = root[MASK] ?? (root[MASK] = [0, 0]);
        state[VALUE] = 'P' + mask[0] + '-' + mask[1]++;
    }
    return state[VALUE];
}
// background hooks
const useEffect = noop;
const useLayoutEffect = noop;
const useImperativeHandle = noop;
export { useCallback, useContext, useDebugValue, useEffect, useErrorBoundary, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, };
//# sourceMappingURL=mainThread.js.map