(function () {
    var imageCache = {};
    var binaryCache = {};
    var imagePattern = /\.(png|jpe?g|gif|webp|svg|avif)(\?|#|$)/i;
    var svgaPattern = /\.svga(\?|#|$)/i;

    function each(nodes, iteratee) {
        Array.prototype.forEach.call(nodes || [], iteratee);
    }

    function normalizeURL(url, baseURL) {
        var value = String(url || '').trim();
        if (
            !value ||
            value.indexOf('data:') === 0 ||
            value.indexOf('blob:') === 0
        ) {
            return '';
        }
        try {
            return new URL(value, baseURL || window.location.href).href;
        } catch (_) {
            return '';
        }
    }

    function addURL(list, seen, url, baseURL) {
        var normalized = normalizeURL(url, baseURL);
        if (!normalized || seen[normalized]) return;
        seen[normalized] = true;
        list.push(normalized);
    }

    function collectFromCSSText(list, seen, text) {
        var pattern = /url\((['"]?)(.*?)\1\)/g;
        var match;
        while ((match = pattern.exec(text || ''))) {
            addURL(list, seen, match[2]);
        }
    }

    function collectSrcSet(list, seen, value) {
        String(value || '')
            .split(',')
            .forEach(function (item) {
                addURL(list, seen, item.trim().split(/\s+/)[0]);
            });
    }

    function collectDocumentURLs(list, seen) {
        each(document.querySelectorAll('img[src]'), function (img) {
            addURL(list, seen, img.getAttribute('src'));
        });
        each(document.querySelectorAll('source[srcset]'), function (source) {
            collectSrcSet(list, seen, source.getAttribute('srcset'));
        });
        each(document.querySelectorAll('style'), function (node) {
            collectFromCSSText(list, seen, node.textContent || '');
        });
        each(document.querySelectorAll('[style]'), function (node) {
            collectFromCSSText(list, seen, node.getAttribute('style') || '');
        });
        each(document.styleSheets, function (sheet) {
            try {
                each(sheet.cssRules || [], function (rule) {
                    collectFromCSSText(list, seen, rule.cssText || '');
                });
            } catch (_) {}
        });
    }

    function collectResourceURLs(assetURLs) {
        var list = [];
        var seen = {};
        (assetURLs || []).forEach(function (url) {
            addURL(list, seen, url);
        });
        collectDocumentURLs(list, seen);
        return list;
    }

    function isImageURL(url) {
        return imagePattern.test(String(url || ''));
    }

    function isSVGAURL(url) {
        return svgaPattern.test(String(url || ''));
    }

    function preloadImage(url) {
        var normalized = normalizeURL(url);
        if (!normalized) return Promise.resolve(false);
        if (imageCache[normalized]) return imageCache[normalized];
        imageCache[normalized] = new Promise(function (resolve) {
            var image = new Image();
            image.onload = function () {
                resolve(true);
            };
            image.onerror = function () {
                resolve(false);
            };
            image.decoding = 'async';
            image.src = normalized;
            if (image.complete) resolve(true);
        });
        return imageCache[normalized];
    }

    function preloadBinary(url) {
        var normalized = normalizeURL(url);
        if (!normalized) return Promise.resolve(false);
        if (binaryCache[normalized]) return binaryCache[normalized];
        binaryCache[normalized] = window
            .fetch(normalized, { cache: 'force-cache' })
            .then(function (response) {
                return response.ok;
            })
            .catch(function () {
                return false;
            });
        return binaryCache[normalized];
    }

    function preloadSVGA(url, options) {
        options = options || {};
        if (
            window.HyAppEffectPlayer &&
            typeof window.HyAppEffectPlayer.preload === 'function'
        ) {
            return window.HyAppEffectPlayer.preload(url, {
                type: 'svga',
                svgaScript: options.svgaScript,
                waitForWindowLoad: options.waitForWindowLoad === true,
            })
                .then(function () {
                    return true;
                })
                .catch(function () {
                    return preloadBinary(url);
                });
        }
        return preloadBinary(url);
    }

    function preloadResource(url, options) {
        if (isSVGAURL(url)) return preloadSVGA(url, options && options.svga);
        if (isImageURL(url)) return preloadImage(url);
        return preloadBinary(url);
    }

    function setProgress(progress) {
        var options =
            typeof progress === 'number'
                ? { progress: progress }
                : progress || {};
        var root = options.root || document.documentElement;
        var safeProgress = Math.min(
            Math.max(Number(options.progress) || 0, 0),
            1
        );
        var progressNode =
            options.progressNode ||
            document.querySelector('[data-role="loading-progress"]');
        root.style.setProperty('--loading-progress', safeProgress.toFixed(4));
        if (progressNode) {
            progressNode.setAttribute(
                'aria-valuenow',
                String(Math.round(safeProgress * 100))
            );
        }
    }

    function runTasks(tasks, onProgress) {
        var completed = 0;
        var total = Math.max((tasks && tasks.length) || 0, 1);
        var update =
            typeof onProgress === 'function'
                ? onProgress
                : function (value) {
                      setProgress(value);
                  };
        update(0);
        if (!tasks || !tasks.length) {
            update(1);
            return Promise.resolve([]);
        }
        // 资源预加载是体验优化，单个资源失败不应该卡死大厅；失败项会返回 false，进度仍然推进。
        return Promise.all(
            tasks.map(function (task) {
                return Promise.resolve()
                    .then(task)
                    .catch(function () {
                        return false;
                    })
                    .then(function (value) {
                        completed += 1;
                        update(completed / total);
                        return value;
                    });
            })
        );
    }

    function complete(options) {
        options = options || {};
        var loadingScreen =
            options.loadingScreen ||
            document.querySelector('[data-role="loading-screen"]');
        setProgress({
            root: options.root,
            progress: 1,
            progressNode: options.progressNode,
        });
        if (loadingScreen) {
            loadingScreen.classList.add('is-complete');
            loadingScreen.setAttribute('aria-hidden', 'true');
        }
        if (options.frame) {
            options.frame.classList.remove('is-preloading');
        }
    }

    function once(task) {
        var promise = null;
        return function () {
            if (!promise) {
                promise = Promise.resolve().then(task);
            }
            return promise;
        };
    }

    function delay(ms) {
        return new Promise(function (resolve) {
            window.setTimeout(resolve, ms);
        });
    }

    window.HyAppGamePreloader = {
        addURL: addURL,
        collectResourceURLs: collectResourceURLs,
        complete: complete,
        delay: delay,
        isImageURL: isImageURL,
        isSVGAURL: isSVGAURL,
        normalizeURL: normalizeURL,
        once: once,
        preloadBinary: preloadBinary,
        preloadImage: preloadImage,
        preloadResource: preloadResource,
        preloadSVGA: preloadSVGA,
        runTasks: runTasks,
        setProgress: setProgress,
    };
})();
