const MakaiSideListEmptyElement = function(element) {
    if(!(element instanceof Element))
        element = <div class="sidelist-empty">
            <div class="sidelist-empty-icon">※</div>
            <div class="sidelist-empty-label">Nothing yet!</div>
        </div>;

    const iconElem = element.querySelector('.sidelist-empty-icon');
    const labelElem = element.querySelector('.sidelist-empty-label');

    return {
        get element() { return element; },

        get icon() { return iconElem.textContent; },
        set icon(value) {
            iconElem.textContent = value;
        },

        get label() { return labelElem.textContent; },
        set label(value) {
            labelElem.textContent = value;
        },
    };
};

const MakaiSideListItemElement = function(element, icon, link, click) {
    const linkClass = 'sidelist-item-link';

    if(!(element instanceof Element)) {
        element = <a class="sidelist-item">
            <div class="sidelist-item-icon">{icon ?? (Math.random() < 0.5 ? '☆' : '★')}</div>
            <div class="sidelist-item-label">{element ?? ''}</div>
        </a>;

        if(typeof link === 'string') {
            element.classList.add(linkClass);
            element.href = link;
        }

        if(typeof click === 'function')
            element.onclick = click;
    }

    const isLink = () => element.classList.contains(linkClass);

    const iconElem = element.querySelector('.sidelist-item-icon');
    const labelElem = element.querySelector('.sidelist-item-label');

    return {
        get element() { return element; },
        get isLink() { return isLink(); },

        get link() { return element.href ?? ''; },
        set link(value) {
            if(value === undefined)
                value = null;

            element.href = value;
            element.classList.toggle(linkClass, typeof value === 'string' && value !== '');
        },

        get icon() { return iconElem.textContent; },
        set icon(value) {
            iconElem.textContent = value;
        },

        get label() { return labelElem.textContent; },
        set label(value) {
            labelElem.textContent = value;
        },
    };
};

const MakaiSideListElement = function(element) {
    if(!(element instanceof Element))
        element = <div class="sidelist">
            <div class="sidelist-title">{element ?? ''}</div>
            <div class="sidelist-body"/>
        </div>;

    const titleElem = element.querySelector('.sidelist-title');
    const bodyElem = element.querySelector('.sidelist-body');
    const emptyElem = new MakaiSideListEmptyElement(bodyElem.querySelector('.sidelist-empty'));

    const getBodyChildren = () => {
        const elems = [];
        for(const elem of bodyElem.children) {
            let item = elem;
            if(item.classList.contains('sidelist-empty'))
                item = new MakaiSideListEmptyElement(item);
            else if(item.classList.contains('sidelist-item'))
                item = new MakaiSideListItemElement(item);
            elems.push(item);
        }
        return elems;
    };

    const insertEmptyElement = () => {
        if(!bodyElem.contains(emptyElem.element) && bodyElem.childElementCount < 1)
            bodyElem.appendChild(emptyElem.element);
    };
    const clearEmptyElement = () => {
        if(bodyElem.contains(emptyElem.element))
            bodyElem.removeChild(emptyElem.element);
    };

    const clearBody = insertEmpty => {
        $rc(bodyElem);
        insertEmptyElement();
    };

    const addItemCommon = (item, ...args) => {
        if(typeof item === 'string')
            item = new MakaiSideListItemElement(item, ...args);
        else if(typeof item !== 'object' || item === null)
            throw 'item must be a non-null object';

        const elem = 'element' in item ? item.element : item;
        if(bodyElem.contains(elem))
            return;

        clearEmptyElement();
        return {
            item: item,
            elem: elem,
        };
    };
    const appendItem = (...args) => {
        const common = addItemCommon(...args);
        if(common === undefined)
            return;

        bodyElem.appendChild(common.elem);
        return common.item;
    };
    const prependItem = (...args) => {
        const common = addItemCommon(...args);
        if(common === undefined)
            return;

        bodyElem.insertBefore(common.elem, bodyElem.firstChild);
        return common.item;
    };

    const removeItem = item => {
        const elem = 'element' in item ? item.element : item;
        if(bodyElem.contains(elem))
            bodyElem.removeChild(elem);

        insertEmptyElement();
        return item;
    };

    if(bodyElem.childElementCount < 1)
        insertEmptyElement();

    return {
        get element() { return element; },
        get titleElem() { return titleElem; },
        get bodyElem() { return bodyElem; },
        get emptyElem() { return emptyElem; },
        get children() { return getBodyChildren(); },

        get title() { return titleElem.textContent; },
        set title(value) {
            titleElem.textContent = value;
        },

        appendItem: appendItem,
        prependItem: prependItem,
        removeItem: removeItem,
    };
};
