import { findIDKey, getNode, isArray, isFunction, optimized } from '@legendapp/state';
import { createElement, memo, useMemo, useRef } from 'react';
import { observer } from './reactive-observer';
import { useSelector } from './useSelector';
const autoMemoCache = new Map();
export function For({ each, eachValues, optimized: isOptimized, item, itemProps, sortValues, children, }) {
    var _a;
    if (!each && !eachValues)
        return null;
    if (eachValues) {
        each = eachValues;
        if (process.env.NODE_ENV === 'development') {
            console.log('[legend-state]: "eachValues" prop is deprecated and will be removed in the next major version. Please use "each" prop instead.');
        }
    }
    const obs = each || eachValues;
    // Get the raw value with a shallow listener so this list only re-renders
    // when the array length changes
    const value = useSelector(() => obs.get(isOptimized ? optimized : true));
    // The child function gets wrapped in a memoized observer component
    if (!item && children) {
        // Update the ref so the generated component uses the latest function
        const refChildren = useRef();
        refChildren.current = children;
        item = useMemo(() => observer(({ item }) => refChildren.current(item)), []);
    }
    else {
        // @ts-expect-error $$typeof is private
        if (item.$$typeof !== Symbol.for('react.memo')) {
            let memod = autoMemoCache.get(item);
            if (!memod) {
                memod = memo(item);
                autoMemoCache.set(item, memod);
            }
            item = memod;
        }
    }
    // This early out needs to be after any hooks
    if (!value)
        return null;
    // Create the child elements
    const out = [];
    const isArr = isArray(value);
    if (isArr) {
        // Get the appropriate id field
        const v0 = value[0];
        const node = getNode(obs);
        const length = value.length;
        const idField = length > 0
            ? (node && findIDKey(v0, node)) ||
                (v0.id !== undefined ? 'id' : v0.key !== undefined ? 'key' : undefined)
            : undefined;
        const isIdFieldFunction = isFunction(idField);
        for (let i = 0; i < length; i++) {
            if (value[i]) {
                const val = value[i];
                const key = (_a = (isIdFieldFunction ? idField(val) : val[idField])) !== null && _a !== void 0 ? _a : i;
                const props = { key, id: key, item: each[i] };
                out.push(createElement(item, itemProps ? Object.assign(props, itemProps) : props));
            }
        }
    }
    else {
        // Render the values of the object / Map
        const isMap = value instanceof Map;
        const keys = isMap ? Array.from(value.keys()) : Object.keys(value);
        if (sortValues) {
            keys.sort((A, B) => sortValues(isMap ? value.get(A) : value[A], isMap ? value.get(B) : value[B], A, B));
        }
        for (let i = 0; i < keys.length; i++) {
            const key = keys[i];
            if (isMap ? value.get(key) : value[key]) {
                const props = {
                    key,
                    id: key,
                    item: isMap ? each.get(key) : each[key],
                };
                out.push(createElement(item, itemProps ? Object.assign(props, itemProps) : props));
            }
        }
    }
    return out;
}
//# sourceMappingURL=For.jsx.map