const CACHE_PREFIX = 'v3d-app-manager-cache-';
const CACHE_VERSION = 'v3';

const CONN_ERR_URL = '/connection_error';

const CONN_ERR_ASSETS = [
    '/manager/css/fonts.css',
    '/manager/css/common.css',
    '/manager/js/common.js',
    '/manager/js/qrcode.js',
    '/manager/img/banner.svg',
    '/manager/fonts/Rubik-Regular.woff',
    '/manager/img/favicons/manifest.json',
    '/manager/img/favicons/favicon-48x48.png',
    '/manager/img/favicons/android-chrome-192x192.png',
];

// low case
const IGNORE_RESOURCES = [
    '.js',
    '.css',
    '.png',
    '.jpg',
    '.jpeg',
    '.svg',
    '.webp',
    '.hdr',
    '.json',
    '.xml',
    '.gltf',
    '.bin',
    '.glb',
    '.mp3',
    '.wav',
    '.mp4',
    '.webm',
    '.xz',
    '.ktx2',
    '.wasm',
    '.ttf',
    '.woff',
    '.csv',
    '.plug', // plugins
    '.block', // plugins
    '/network/upload',
    '/network/download',
    '/network/delete',
    '/network/progress',
    '/network/cancel',
    '/settings/do_show_splash',
    '/settings/is_runtime_outdated',
    '/store/download',
    '/store/cancel',
    '/ping',
    '/stop',
    '/restart',
    '/reset',
    '/select_dir',
    '/get_preview_dir'
];

self.addEventListener('install', (event) => {

    event.waitUntil(caches.open(CACHE_PREFIX + CACHE_VERSION).then(cache => {
        return cache.addAll([CONN_ERR_URL].concat(CONN_ERR_ASSETS));
    }));

    console.log('Verge3D App Manager worker installed');

});


const deleteCache = async (key) => {
    await caches.delete(key);
};

const deleteOldCaches = async () => {
    const keyList = await caches.keys();
    const cachesToDelete = keyList.filter((key) => {
        return (key.includes(CACHE_PREFIX) && !key.includes(CACHE_PREFIX + CACHE_VERSION));
    });
    await Promise.all(cachesToDelete.map(deleteCache));
};

self.addEventListener('activate', (event) => {
    event.waitUntil(deleteOldCaches());
});

async function handleDisconnection(request) {

    try {

        const responseFromNetwork = await fetch(request);
        return responseFromNetwork;

    } catch (error) {

        let fallbackResponse = await caches.match(request);
        if (fallbackResponse) {
            return fallbackResponse;
        }

        fallbackResponse = await caches.match(CONN_ERR_URL);
        if (fallbackResponse) {
            return new Response(fallbackResponse.body, {
                status: 404,
                headers: fallbackResponse.headers
            });
        }

        return new Response('Network error happened', {
            status: 408,
            headers: { 'Content-Type': 'text/plain' }
        });

    }

}

self.addEventListener('fetch', (event) => {
    const url = new URL(event.request.url);
    const pathname = url.pathname;

    // prevent serving external resources
    if (!['8668', '8669', '8670'].includes(url.port))
        return;

    // if passed further, causes 404 errors printed in the browser console
    // reproduced for newer versions of Chrome/Edge
    if (event.request.cache === 'only-if-cached')
        return;

    // do not ignore assets required for error page
    for (let i = 0; i < CONN_ERR_ASSETS.length; i++) {
        if (pathname == CONN_ERR_ASSETS[i]) {
            event.respondWith(handleDisconnection(event.request));
            return;
        }
    }

    for (let i = 0; i < IGNORE_RESOURCES.length; i++)
        if (pathname.toLowerCase().endsWith(IGNORE_RESOURCES[i]))
            return;

    event.respondWith(handleDisconnection(event.request));
});
