"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useInfiniteQuery = void 0;
const react_1 = require("react");
const stub = (y) => undefined;
const useInfiniteQuery = ({ query, getQueryItems, rowHeight, itemCount, height, limit = Math.ceil(height / rowHeight), treshold = 0, queryId = '0', delay = 100, sortOptions, }) => {
    const blockHeight = rowHeight * limit;
    const [, setChecksum] = (0, react_1.useState)('');
    const [offset, setOffset] = (0, react_1.useState)(0);
    const [blocks, setBlocks] = (0, react_1.useState)(() => {
        let blocks = Math.ceil(height / blockHeight);
        if (treshold) {
            blocks += Math.ceil((height / rowHeight + treshold - blocks * limit) / limit);
        }
        return blocks;
    });
    const { current } = (0, react_1.useRef)({
        items: [],
        scrollY: 0,
        timer: null,
        subs: {},
        offset: 0,
        blocks: 0,
    });
    (0, react_1.useEffect)(() => {
        current.items = [];
    }, [queryId]);
    (0, react_1.useEffect)(() => {
        return () => {
            const { subs } = current;
            for (const subId in subs) {
                subs[subId]();
            }
            current.subs = {};
        };
    }, [current]);
    if (!query) {
        (0, react_1.useEffect)(() => { }, []);
        (0, react_1.useEffect)(() => { }, []);
        return {
            loading: false,
            itemCount: 0,
            items: [],
            onScrollY: stub,
            cache: current,
        };
    }
    (0, react_1.useEffect)(() => {
        const subs = {};
        let i = blocks;
        while (i--) {
            const start = offset + limit * i;
            const q = query(start, limit, sortOptions);
            subs[q.id] =
                current.subs[q.id] ||
                    q.subscribe((data, checksum) => {
                        const items = getQueryItems(data) ?? data.items ?? [];
                        for (let i = 0; i < items.length; i++) {
                            current.items[i + start] = items[i];
                        }
                        // make this more complex put more in (all ranges + checksums)
                        setChecksum(`${offset}-${checksum}`);
                    });
        }
        for (const subId in current.subs) {
            if (!(subId in subs)) {
                current.subs[subId]();
            }
        }
        current.subs = subs;
    }, [offset, blocks, current, queryId]);
    (0, react_1.useEffect)(update, [
        blockHeight,
        delay,
        height,
        rowHeight,
        current,
        limit,
        treshold,
    ]);
    return {
        loading: !itemCount || !current.items.length,
        itemCount,
        items: current.items,
        cache: current,
        onScrollY: (scrollY) => {
            if (current.scrollY !== scrollY) {
                current.scrollY = scrollY;
                update();
            }
        },
    };
    function update() {
        const start = Math.max(0, current.scrollY / rowHeight - treshold);
        const end = (current.scrollY + height) / rowHeight;
        const newOffset = start - (start % limit);
        let newBlocks = Math.ceil(height / blockHeight + (current.scrollY % blockHeight) / blockHeight);
        if (treshold) {
            const newLength = newOffset + limit * newBlocks;
            newBlocks += Math.max(0, Math.ceil((end + treshold - newLength) / limit));
        }
        if (newOffset !== current.offset || newBlocks !== current.blocks) {
            current.offset = newOffset;
            current.blocks = newBlocks;
            const set = () => {
                setOffset(current.offset);
                setBlocks(current.blocks);
            };
            if (current.timer) {
                clearTimeout(current.timer);
            }
            else {
                set();
            }
            current.timer = setTimeout(() => {
                current.timer = null;
                set();
            }, delay);
        }
        else if (current.timer) {
            clearTimeout(current.timer);
            current.timer = setTimeout(() => {
                current.timer = null;
                setOffset(current.offset);
                setBlocks(current.blocks);
            }, delay);
        }
    }
};
exports.useInfiniteQuery = useInfiniteQuery;
//# sourceMappingURL=useInfiniteQuery.js.map