import { createComponentOptionsManager, isPromise, findIndexOfMaybeRefArray, pushMaybeRefArrayValue, spliceMaybeRefArray, extendMaybeRefArrayValue, isObject, setMaybeRefValue, hasOwnProperty, hasNormalizedSlot, normalizeSlot, evaluateFnOrValue, installStoreManager, applyStoreManagerOptions } from '@vuecs/core';
import { unref, isRef, isReactive, h, mergeProps } from 'vue';
import { merge } from 'smob';

function boolableToObject(input) {
    if (typeof input === 'boolean') {
        return {};
    }
    return input;
}

var Component;
(function(Component) {
    Component["List"] = "list";
    Component["ListFooter"] = "listFooter";
    Component["ListHeader"] = "listHeader";
    Component["ListItem"] = "listItem";
    Component["ListBody"] = "listBody";
    Component["ListLoading"] = "listLoading";
    Component["ListNoMore"] = "listNoMore";
})(Component || (Component = {}));
var SlotName;
(function(SlotName) {
    SlotName["DEFAULT"] = "default";
    SlotName["FOOTER"] = "footer";
    SlotName["HEADER"] = "header";
    SlotName["BODY"] = "body";
    SlotName["LOADING"] = "loading";
    SlotName["NO_MORE"] = "noMore";
    SlotName["ITEM"] = "item";
    SlotName["ITEM_ACTIONS"] = "itemActions";
    SlotName["ITEM_ACTIONS_EXTRA"] = "itemActionsExtra";
})(SlotName || (SlotName = {}));

function buildListBaseOptions(options, component, defaults) {
    defaults = defaults || {};
    const manager = createComponentOptionsManager({
        name: component
    });
    return {
        slotItems: options.slotItems || {},
        slotProps: manager.buildOrFail({
            key: 'slotProps',
            value: options.slotProps,
            alt: defaults.slotProps || {}
        }),
        slotPropsBuilt: options.slotPropsBuilt,
        tag: manager.buildOrFail({
            key: 'tag',
            value: options.tag,
            alt: defaults.tag || 'div'
        }),
        class: manager.buildOrFail({
            key: 'class',
            value: options.class,
            alt: defaults.class || []
        }),
        props: manager.buildOrFail({
            key: 'props',
            value: options.props,
            alt: defaults.props || {}
        }),
        total: options.total,
        load: options.load,
        meta: options.meta || {},
        busy: options.busy,
        itemId: options.itemId,
        itemKey: options.itemKey,
        onCreated: options.onCreated,
        onUpdated: options.onUpdated,
        onDeleted: options.onDeleted
    };
}
const buildFilterFn = (item, itemId, itemKey)=>{
    let filterFn;
    if (itemId) {
        filterFn = (el)=>itemId(el) === itemId(item);
    }
    if (itemKey) {
        filterFn = (el)=>{
            if (typeof itemKey === 'function') {
                return el[itemKey(el)] === item[itemKey(item)];
            }
            return el[itemKey] === item[itemKey];
        };
    }
    if (!filterFn && isObject(item) && hasOwnProperty(item, 'id')) {
        filterFn = (el)=>el['id'] === item['id'];
    }
    return filterFn;
};
function buildListBaseSlotProps(ctx) {
    const props = {};
    if (typeof ctx.busy !== 'undefined') {
        props.busy = unref(ctx.busy);
    }
    if (typeof ctx.meta !== 'undefined') {
        props.meta = ctx.meta;
    }
    if (typeof ctx.total !== 'undefined') {
        props.total = unref(ctx.total);
    }
    const incrTotal = ()=>{
        if (typeof ctx.total === 'undefined') {
            return;
        }
        if (isRef(ctx.total)) {
            ctx.total.value++;
            props.total = ctx.total.value;
        }
    };
    const decrTotal = ()=>{
        if (typeof ctx.total === 'undefined') {
            return;
        }
        if (isRef(ctx.total)) {
            ctx.total.value--;
            props.total = ctx.total.value;
        }
    };
    if (typeof ctx.load === 'function') {
        props.load = (meta)=>{
            if (!isRef(ctx.busy)) {
                return ctx.load(meta);
            }
            ctx.busy.value = true;
            const output = ctx.load(meta);
            if (isPromise(output)) {
                return output.finally(()=>{
                    if (isRef(ctx.busy)) {
                        ctx.busy.value = false;
                    }
                });
            }
            ctx.busy.value = false;
            return output;
        };
    }
    props.created = (item)=>{
        if (typeof ctx.data === 'undefined') {
            if (typeof ctx.onCreated === 'function') {
                ctx.onCreated(item);
            }
            incrTotal();
            return;
        }
        const data = unref(ctx.data);
        if (Array.isArray(data)) {
            const filterFn = buildFilterFn(item, ctx.itemId, ctx.itemKey);
            if (filterFn) {
                const index = findIndexOfMaybeRefArray(ctx.data, filterFn);
                if (index === -1) {
                    pushMaybeRefArrayValue(ctx.data, item);
                    incrTotal();
                    if (typeof ctx.onCreated === 'function') {
                        ctx.onCreated(item);
                    }
                }
            }
        } else {
            incrTotal();
            if (typeof ctx.onCreated === 'function') {
                ctx.onCreated(item);
            }
        }
    };
    props.deleted = (item)=>{
        if (typeof ctx.data === 'undefined') {
            if (typeof ctx.onDeleted === 'function' && item) {
                ctx.onDeleted(item);
            }
            decrTotal();
            return;
        }
        const data = unref(ctx.data);
        if (Array.isArray(data)) {
            if (item) {
                const filterFn = buildFilterFn(item, ctx.itemId, ctx.itemKey);
                if (filterFn) {
                    const index = findIndexOfMaybeRefArray(ctx.data, filterFn);
                    if (index !== -1) {
                        spliceMaybeRefArray(ctx.data, index, 1);
                        decrTotal();
                        if (typeof ctx.onDeleted === 'function') {
                            if (item) {
                                ctx.onDeleted(item);
                            } else {
                                ctx.onDeleted(data[index]);
                            }
                        }
                    }
                }
            }
        } else {
            decrTotal();
            if (typeof ctx.onDeleted === 'function') {
                if (item) {
                    ctx.onDeleted(item);
                } else {
                    ctx.onDeleted(data);
                }
            }
        }
    };
    props.updated = (item)=>{
        if (typeof ctx.data === 'undefined') {
            if (typeof ctx.onUpdated === 'function') {
                ctx.onUpdated(item);
            }
            return;
        }
        let data = unref(ctx.data);
        if (Array.isArray(data)) {
            const filterFn = buildFilterFn(item, ctx.itemId, ctx.itemKey);
            if (filterFn) {
                const index = findIndexOfMaybeRefArray(ctx.data, filterFn);
                if (index !== -1) {
                    extendMaybeRefArrayValue(ctx.data, index, item);
                    if (typeof ctx.onUpdated === 'function') {
                        ctx.onUpdated(item); // todo: extend with data
                    }
                }
            }
        } else {
            if (isObject(item) && isObject(data)) {
                data = merge(item, data);
            } else {
                data = item;
            }
            if (isReactive(ctx.data)) {
                ctx.data = data;
            } else {
                setMaybeRefValue(ctx.data, data);
            }
            if (typeof ctx.onUpdated === 'function') {
                ctx.onUpdated(data);
            }
        }
    };
    return props;
}

function buildListFooterOptions(input) {
    const options = buildListBaseOptions(input, Component.ListFooter, {
        class: 'list-footer'
    });
    const manager = createComponentOptionsManager({
        name: Component.ListFooter
    });
    return {
        ...options,
        content: manager.buildOrFail({
            key: 'content',
            value: input.content,
            alt: []
        })
    };
}
function buildListFooter(input) {
    input = input || {};
    const options = buildListFooterOptions(input);
    let slotProps;
    if (options.slotPropsBuilt) {
        slotProps = options.slotProps;
    } else {
        slotProps = {
            ...buildListBaseSlotProps(options),
            ...options.slotProps
        };
    }
    let children = [];
    if (hasNormalizedSlot(SlotName.FOOTER, options.slotItems)) {
        children = [
            normalizeSlot(SlotName.FOOTER, slotProps, options.slotItems)
        ];
    } else if (options.content) {
        if (typeof options.content === 'function') {
            children = [
                options.content(slotProps)
            ];
        } else {
            children = [
                options.content
            ];
        }
    }
    if (children.length > 0) {
        return h(options.tag, mergeProps({
            class: options.class
        }, options.props), [
            children
        ]);
    }
    return [];
}

function buildListHeaderOptions(input) {
    const options = buildListBaseOptions(input, Component.ListHeader, {
        class: 'list-header'
    });
    const manager = createComponentOptionsManager({
        name: Component.ListHeader
    });
    return {
        ...options,
        content: manager.buildOrFail({
            key: 'content',
            value: input.content,
            alt: []
        })
    };
}
function buildListHeader(input) {
    input = input || {};
    const options = buildListHeaderOptions(input);
    let slotProps;
    if (options.slotPropsBuilt) {
        slotProps = options.slotProps;
    } else {
        slotProps = {
            ...buildListBaseSlotProps(options),
            ...options.slotProps
        };
    }
    let content = [];
    if (hasNormalizedSlot(SlotName.HEADER, options.slotItems)) {
        content = [
            normalizeSlot(SlotName.HEADER, slotProps, options.slotItems)
        ];
    } else if (options.content) {
        if (typeof options.content === 'function') {
            content = [
                options.content(slotProps)
            ];
        } else {
            content = [
                options.content
            ];
        }
    }
    if (content.length > 0) {
        return h(options.tag, mergeProps({
            class: options.class
        }, options.props), [
            content
        ]);
    }
    return [];
}

function buildListItemOptions(input) {
    const options = buildListBaseOptions(input, Component.ListItem, {
        class: 'list-item',
        tag: 'li'
    });
    const manager = createComponentOptionsManager({
        name: Component.ListItem
    });
    return {
        ...options,
        data: input.data,
        content: input.content,
        index: input.index,
        icon: manager.buildOrFail({
            key: 'icon',
            value: input.icon,
            alt: true
        }),
        iconTag: manager.buildOrFail({
            key: 'iconTag',
            value: input.iconTag,
            alt: 'i'
        }),
        iconClass: manager.buildOrFail({
            key: 'iconClass',
            value: input.iconClass,
            alt: []
        }),
        iconProps: input.iconProps || {},
        iconWrapper: manager.buildOrFail({
            key: 'iconWrapper',
            value: input.iconWrapper,
            alt: true
        }),
        iconWrapperClass: manager.buildOrFail({
            key: 'iconWrapperClass',
            value: input.iconWrapperClass,
            alt: []
        }),
        iconWrapperTag: manager.buildOrFail({
            key: 'iconWrapperTag',
            value: input.iconWrapperTag,
            alt: 'div'
        }),
        text: manager.buildOrFail({
            key: 'text',
            value: input.text,
            alt: true
        }),
        textContent: input.textContent,
        textPropName: manager.buildOrFail({
            key: 'textPropName',
            value: input.textPropName,
            alt: 'name'
        }),
        textWrapper: manager.buildOrFail({
            key: 'textWrapper',
            value: input.textWrapper,
            alt: true
        }),
        textWrapperClass: manager.buildOrFail({
            key: 'textWrapperClass',
            value: input.textWrapperClass,
            alt: []
        }),
        textWrapperTag: manager.buildOrFail({
            key: 'textWrapperTag',
            value: input.textWrapperTag,
            alt: 'div'
        }),
        actions: manager.buildOrFail({
            key: 'actions',
            value: input.actions,
            alt: true
        }),
        actionsContent: manager.buildOrFail({
            key: 'actionsContent',
            value: input.actionsContent,
            alt: []
        }),
        actionsWrapper: manager.buildOrFail({
            key: 'actionsWrapper',
            value: input.actionsWrapper,
            alt: true
        }),
        actionsWrapperClass: manager.buildOrFail({
            key: 'actionsWrapperClass',
            value: input.actionsWrapperClass,
            alt: []
        }),
        actionsWrapperTag: manager.buildOrFail({
            key: 'actionsWrapperTag',
            value: input.actionsWrapperTag,
            alt: 'div'
        })
    };
}
function maybeWrapContent(input, ctx) {
    if (!ctx.wrap) {
        return input;
    }
    return h(ctx.tag, {
        class: ctx.class
    }, [
        input
    ]);
}
function buildListItem(input) {
    const options = buildListItemOptions(input);
    let data = unref(options.data);
    const overrideUpdatedFn = (fn, item)=>{
        if (typeof item === 'undefined') {
            return fn(data);
        }
        if (isObject(item) && isObject(data)) {
            data = merge(item, data);
        } else {
            data = item;
        }
        if (isReactive(options.data)) {
            options.data = data;
            return fn(data);
        }
        setMaybeRefValue(options.data, data);
        return fn(data);
    };
    let slotProps;
    if (options.slotPropsBuilt) {
        const { updated, deleted, ...original } = options.slotProps;
        slotProps = {
            ...original,
            data,
            index: options.index
        };
        if (updated) {
            slotProps.updated = (item)=>overrideUpdatedFn(updated, item);
        }
        if (deleted) {
            slotProps.deleted = (item)=>deleted(item || data);
        }
    } else {
        const { updated, deleted, ...original } = buildListBaseSlotProps({
            ...options,
            data: options.data
        });
        slotProps = {
            ...original,
            data,
            index: options.index
        };
        if (updated) {
            slotProps.updated = (item)=>overrideUpdatedFn(updated, item);
        }
        if (deleted) {
            slotProps.deleted = (item)=>deleted(item || data);
        }
    }
    const renderContent = (content)=>h(options.tag, mergeProps({
            key: options.index
        }, {
            class: options.class
        }, options.props), [
            content || []
        ]);
    const children = {};
    if (hasNormalizedSlot(SlotName.ITEM, options.slotItems)) {
        children.slot = normalizeSlot(SlotName.ITEM, slotProps, options.slotItems);
    } else {
        if (options.icon) {
            children.icon = maybeWrapContent(h(options.iconTag, mergeProps({
                class: options.iconClass
            }, options.iconProps)), {
                wrap: options.iconWrapper,
                tag: options.iconWrapperTag,
                class: options.iconWrapperClass
            });
        }
        if (options.text) {
            let text;
            if (options.textContent) {
                text = evaluateFnOrValue(options.textContent, data, slotProps);
            } else if (options.textPropName && isObject(data) && hasOwnProperty(data, options.textPropName)) {
                text = data[options.textPropName];
            }
            if (text) {
                children.text = maybeWrapContent(text, {
                    wrap: options.textWrapper,
                    tag: options.textWrapperTag,
                    class: options.textWrapperClass
                });
            }
        }
        let actions;
        if (options.actions) {
            if (hasNormalizedSlot(SlotName.ITEM_ACTIONS, options.slotItems)) {
                actions = [
                    normalizeSlot(SlotName.ITEM_ACTIONS, slotProps, options.slotItems)
                ];
            } else if (options.actionsContent) {
                actions = evaluateFnOrValue(options.actionsContent, data, slotProps);
            }
            if (hasNormalizedSlot(SlotName.ITEM_ACTIONS_EXTRA, options.slotItems)) {
                actions = [
                    actions,
                    normalizeSlot(SlotName.ITEM_ACTIONS_EXTRA, slotProps, options.slotItems)
                ];
            }
        }
        if (actions) {
            children.actions = maybeWrapContent(actions, {
                wrap: options.actionsWrapper,
                tag: options.actionsWrapperTag,
                class: options.actionsWrapperClass
            });
        }
    }
    if (options.content) {
        return renderContent(evaluateFnOrValue(options.content, data, slotProps, children));
    }
    if (children.slot) {
        return renderContent(children.slot);
    }
    const content = [
        ...children.icon ? [
            children.icon
        ] : [],
        ...children.text ? [
            children.text
        ] : [],
        ...children.actions ? [
            children.actions
        ] : []
    ];
    return renderContent(content);
}

function buildListBodyOptions(input) {
    const options = buildListBaseOptions(input, Component.ListBody, {
        class: 'list-body',
        tag: 'ul'
    });
    return {
        ...options,
        data: input.data || [],
        item: input.item
    };
}
function buildListBody(input) {
    input = input || {};
    const options = buildListBodyOptions(input);
    let slotProps;
    if (options.slotPropsBuilt) {
        slotProps = {
            data: unref(options.data),
            ...options.slotProps
        };
    } else {
        slotProps = {
            ...buildListBaseSlotProps(options),
            data: unref(options.data),
            ...options.slotProps
        };
    }
    if (hasNormalizedSlot(SlotName.BODY, options.slotItems)) {
        return h(options.tag, mergeProps({
            class: options.class
        }, options.props), normalizeSlot(SlotName.BODY, slotProps, options.slotItems));
    }
    // ----------------------------------------------------------------------
    const items = unref(options.data);
    if (items.length === 0) {
        return [];
    }
    return h(options.tag, mergeProps({
        class: options.class
    }, options.props), items.map((item, index)=>buildListItem({
            slotProps,
            slotPropsBuilt: true,
            slotItems: options.slotItems,
            ...options.item,
            data: item,
            index,
            busy: options.busy
        })));
}

function buildListLoadingOptions(input) {
    const options = buildListBaseOptions(input, Component.ListLoading, {
        class: 'list-loading'
    });
    return {
        ...options
    };
}
function buildListLoading(input) {
    input = input || {};
    const options = buildListLoadingOptions(input);
    let slotProps;
    if (options.slotPropsBuilt) {
        slotProps = options.slotProps;
    } else {
        slotProps = {
            ...buildListBaseSlotProps(options),
            ...options.slotProps
        };
    }
    if (!options.busy) {
        return [];
    }
    let content;
    if (hasNormalizedSlot(SlotName.LOADING, options.slotItems)) {
        content = normalizeSlot(SlotName.LOADING, slotProps, options.slotItems);
    }
    if (options.content) {
        if (typeof options.content === 'function') {
            content = [
                options.content(slotProps)
            ];
        } else {
            content = [
                options.content
            ];
        }
    }
    if (content) {
        return h(options.tag, mergeProps({
            class: options.class
        }, options.props), [
            content
        ]);
    }
    return [];
}

function buildListNoMoreOptions(input) {
    const options = buildListBaseOptions(input, Component.ListNoMore, {
        class: 'list-no-more'
    });
    const manager = createComponentOptionsManager({
        name: Component.ListNoMore
    });
    return {
        ...options,
        content: manager.buildOrFail({
            key: 'content',
            value: input.content,
            alt: 'No more items available...'
        })
    };
}
function buildListNoMore(input) {
    input = input || {};
    const options = buildListNoMoreOptions(input);
    const busy = unref(options.busy);
    const total = unref(options.total);
    if (busy) {
        return [];
    }
    if (typeof total === 'number') {
        if (total > 0) {
            return [];
        }
    } else if (isObject(options.meta) && hasOwnProperty(options.meta, 'total') && typeof options.meta.total === 'number' && options.meta.total > 0) {
        return [];
    }
    let slotProps;
    if (options.slotPropsBuilt) {
        slotProps = options.slotProps;
    } else {
        slotProps = {
            ...buildListBaseSlotProps(options),
            ...options.slotProps
        };
    }
    const renderContent = (content)=>h(options.tag, mergeProps({
            class: options.class
        }, options.props), [
            content
        ]);
    if (hasNormalizedSlot(SlotName.NO_MORE, options.slotItems)) {
        return renderContent(normalizeSlot(SlotName.NO_MORE, slotProps, options.slotItems));
    }
    if (typeof options.content === 'function') {
        return renderContent(options.content(slotProps));
    }
    return renderContent(options.content);
}

function buildListOptions(input) {
    const options = buildListBaseOptions(input, Component.List, {
        class: 'list'
    });
    return {
        ...options,
        data: input.data ?? [],
        header: input.header ?? true,
        footer: input.footer ?? true,
        body: input.body ?? true,
        loading: input.loading ?? true,
        noMore: input.noMore ?? true
    };
}
function buildList(input) {
    const options = buildListOptions(input);
    if (typeof options.total === 'undefined') {
        options.total = unref(options.data).length;
    }
    const buildSlotProps = (props)=>({
            ...props,
            ...buildListBaseSlotProps(options)
        });
    const extendChildOptions = (input)=>{
        input.slotItems = options.slotItems;
        input.slotProps = buildSlotProps(options.slotProps);
        input.slotPropsBuilt = true;
        input.busy = options.busy;
        input.meta = options.meta;
        input.total = options.total;
        return input;
    };
    if (hasNormalizedSlot(SlotName.DEFAULT, options.slotItems)) {
        const slotProps = {
            ...buildSlotProps(options.slotProps),
            data: unref(options.data)
        };
        return normalizeSlot(SlotName.DEFAULT, slotProps, options.slotItems);
    }
    const children = [];
    if (options.header) {
        children.push(buildListHeader(extendChildOptions(boolableToObject(options.header))));
    }
    if (options.body) {
        let childOptions;
        if (typeof options.body === 'boolean') {
            childOptions = {
                data: options.data,
                busy: options.busy
            };
        } else {
            childOptions = options.body;
            childOptions.data = options.data;
            childOptions.busy = options.busy;
        }
        children.push(buildListBody(extendChildOptions(childOptions)));
    }
    if (options.loading) {
        children.push(buildListLoading(extendChildOptions(boolableToObject(options.loading))));
    }
    if (options.noMore) {
        children.push(buildListNoMore(extendChildOptions(boolableToObject(options.noMore))));
    }
    if (options.footer) {
        children.push(buildListFooter(extendChildOptions(boolableToObject(options.footer))));
    }
    return h(options.tag, mergeProps({
        class: options.class
    }, options.props), children);
}

function install(instance, options = {}) {
    const storeManager = installStoreManager(instance);
    if (options.storeManager) {
        applyStoreManagerOptions(storeManager, options.storeManager);
    }
}
var index = {
    install
};

export { Component, SlotName, buildList, buildListBaseOptions, buildListBaseSlotProps, buildListBody, buildListBodyOptions, buildListFooter, buildListFooterOptions, buildListHeader, buildListHeaderOptions, buildListItem, buildListItemOptions, buildListLoading, buildListLoadingOptions, buildListNoMore, buildListNoMoreOptions, buildListOptions, index as default, install };
//# sourceMappingURL=index.mjs.map
