const MakaiSiteHeaderImages = function() {
    const url = '/header-bgs.json';

    let headers;
    const all = async () => {
        if(!Array.isArray(headers))
            headers = (await $xhr.get('/header-bgs.json', { type: 'json' })).body;

        return headers;
    };

    return {
        all: all,
        random: async () => {
            const images = await all();
            if(images.length < 1)
                return '/flonnerator.png';

            return images[Math.floor(Math.random() * images.length)];
        },
    };
};

const MakaiSiteHeader = function(element) {
    if(!(element instanceof Element))
        throw 'element must be an instance of Element';

    const images = new MakaiSiteHeaderImages;
    const bgElem = element.querySelector('.js-header-background');
    const getBgImgElem = () => bgElem.querySelector('img');

    const setBackgroundImage = (url, duration) => {
        return new Promise((resolve, reject) => {
            if(typeof duration !== 'number')
                duration = 500;

            while(bgElem.childElementCount > 1)
                bgElem.removeChild(bgElem.lastChild);

            const prevImage = getBgImgElem();
            if(prevImage.src === url) {
                resolve();
                return;
            }

            let startTimeStamp;
            const updateTransition = timeStamp => {
                if(startTimeStamp === undefined)
                    startTimeStamp = timeStamp;

                const elapsed = timeStamp - startTimeStamp;
                const t = Math.min(1, Math.max(0, elapsed / duration));

                prevImage.style.opacity = 1 - t;

                if(t < 1)
                    requestAnimationFrame(updateTransition);
                else {
                    prevImage.remove();
                    resolve();
                }
            };

            prevImage.style.zIndex = '2';

            const nextImage = $element(
                'img',
                {
                    alt: url,
                    src: url,
                    onerror: () => {
                        prevImage.style.opacity = null;
                        prevImage.style.zIndex = null;
                        bgElem.removeChild(nextImage);
                        reject();
                    },
                    onload: () => {
                        requestAnimationFrame(updateTransition);
                    },
                },
            );
            bgElem.appendChild(nextImage);
        });
    };

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

        get backgroundElement() { return bgElem; },
        get backgroundImage() { return getBgImgElem().src; },

        setBackgroundImage: setBackgroundImage,
        randomBackgroundImage: async () => {
            await setBackgroundImage(await images.random());
        },
    };
};