var appSw = undefined;
var appServiceWorker = function () {
    let cacheName = 'cache-v639129946268934926';
    let cacheStrategy = 'OnlineFirst';
    let serverPushKey = 'BNaPo9030hZcWCyKNG2GN5-ZqGdTU4LlR68yrRIc2PkT_-tFXu9uMbJRqJkTRJz1PmIJhltSRYMi4JlagWAvdB0';
    let swUrl = '/fa-IR/CEDOWA/app/serviceworker';
    let scope = '/fa-IR/CEDOWA';
    let filesToCache = [];
    let offlineUrl = '<offlineUrl>';
    let offlineUrlAjax = '<offlineUrlAjax>';

    this.getPushKey = function () {
        return serverPushKey;
    }

    this.register = async function () {
        try {
            var reg = await navigator.serviceWorker.register(swUrl, { scope: scope });
            /*serviceWorkerRegistered = true;*/
            return reg;
        } catch (e) {
            console.log(e);
        }
    }

    this.onInstall = async function () {
        var can = await canAutoInstall();
        if (can) {
            await install();
        }

        return undefined;
    }

    this.onActivate = async function () {
        await uninstallOldCaches();
        await self.clients.claim();

        await reportActivated();

        if (await isUpdateAvailable())
            await reportUpdateAvailable();
    }


    var canAutoInstall = async function () {
        if (cacheStrategy === 'OnlineFirst')
            return true;

        var keys = await self.caches.keys();
        if (keys && keys.length < 2)
            return true;

        return false;
    }

    var install = async function () {
        var cache = await caches.open(cacheName);
        var ajaxCache = await caches.open(getAjaxCacheName());

        filesToCache.forEach(async item => {
            if (item.includes('X_Requested_With'))
                await ajaxCache.add(item);
            else
                await cache.add(item);
        });
    }

    var getAjaxCacheName = function () {
        return `${cacheName}-XMLHttpRequest`;
    }

    var getMainCacheKey = async function () {
        try {
            var keys = await self.caches.keys();

            return keys[0];
        } catch (err) {
            return undefined;
        }
    }

    var getAjaxCacheKey = async function () {
        try {
            var keys = await self.caches.keys();

            return keys[1];
        } catch (err) {
            return undefined;
        }
    }
    var uninstallOldCaches = async function () {
        try {
            var keys = await caches.keys();
            if (keys.length > 2) {
                keys.forEach(async key => {
                    if (key !== cacheName && key !== getAjaxCacheName()) {
                        await caches.delete(key);
                    }
                });
            }
        } catch (err) {

        }
    }

    var isUpdateAvailable = async function () {
        var key = await getMainCacheKey();

        if (key !== cacheName)
            return true;

        return false;
    }

    var reportActivated = async function () {
        var allClients = await self.clients.matchAll();
        allClients.forEach(async (c) => {
            await sendMessage(c.id, { msg: "Activated" });
        });
    }

    var reportUpdateAvailable = async function () {
        var allClients = await self.clients.matchAll();
        allClients.forEach(async (c) => {
            await sendMessage(c.id, { msg: "UpdateAvailable" });
        });
    }

    var reportConnectionStatus = async function (clientId, status) {
        await sendMessage(clientId, { msg: "ConnectionStatus", data: status });
    }

    var reportUpdated = async function () {
        var allClients = await self.clients.matchAll();
        allClients.forEach(async (c) => {
            await sendMessage(c.id, { msg: "Updated" });
        });
    }

    var onCheckUpdateMessage = async function () {
        if (await isUpdateAvailable())
            await reportUpdateAvailable();
    }

    var onUpdateMessage = async function () {
        await install();
        await uninstallOldCaches();
        await reportUpdated();
    }

    var sendMessage = async function (clientId, message) {
        try {
            var client = await self.clients.get(clientId);
            client.postMessage(message);
        }
        catch (err) {

        }
    }

    var isAjaxRequest = function (request) {
        var url;
        if (request.url)
            url = request.url;
        else
            url = request;

        if (url.includes('X_Requested_With') || (request.headers && request.headers.has('x-requested-with')))
            return true;

        return false;
    }

    var openCache = async function (openAjax) {
        try {
            var key;
            if (openAjax)
                key = await getAjaxCacheKey();
            else
                key = await getMainCacheKey();

            return await self.caches.open(key);
        } catch (err) {
            return undefined;
        }
    }

    var readCache = async function (request) {
        var isAjax = isAjaxRequest(request);

        var cache = await openCache(isAjax);
        return await cache.match(request);
    }

    var putOnCache = async function (request, clonedResponse) {
        if (request.method === 'GET') {
            var isAjax = isAjaxRequest(request);

            try {
                var cache = await openCache(isAjax);
                cache.put(request, clonedResponse);
            } catch (err) {

            }
        }
    }

    var getOfflineView = async function (request) {
        var isAjax = isAjaxRequest(request);

        var offline = isAjax ? await readCache(offlineUrlAjax) : await readCache(offlineUrl);
        if (offline)
            return offline;

        return undefined;
    }

    var offlineFirst = async function (e) {
        var r = await readCache(e.request);
        if (r)
            return r;

        try {
            var response = await fetch(e.request);

            await reportConnectionStatus(e.clientId, true);
            await putOnCache(e.request, response.clone());

            return response;
        } catch (err) {
            await reportConnectionStatus(e.clientId, false);
            return await getOfflineView(e.request);
        }
    }

    var onlineFirst = async function (e) {
        try {
            var response = await fetch(e.request);

            await reportConnectionStatus(e.clientId, true);
            await putOnCache(e.request, response.clone());

            return response;
        }
        catch (err) {
            await reportConnectionStatus(e.clientId, false);
            var r = await readCache(e.request);
            if (r)
                return r;

            return await getOfflineView(e.request);
        }
    }

    function init() {
        self.addEventListener('fetch', (e) => {
            if (e.request.method === 'GET') {
                var requestUrl = new URL(e.request.url);
                if (requestUrl.host === "www.google-analytics.com") {
                    e.respondWith(fetch(e.request));
                } else if (cacheStrategy === 'OfflineFirst') {
                    e.respondWith(offlineFirst(e));
                } else {
                    e.respondWith(onlineFirst(e));
                }
            }
        });

        self.addEventListener('message', async (event) => {
            if (event.data) {
                switch (event.data.msg) {
                    case 'CheckUpdate':
                        await onCheckUpdateMessage();
                        break;

                    case 'Update':
                        await onUpdateMessage();
                        break;

                    default:
                        console.log(event);
                }
            }
        });

        self.addEventListener('push', (e) => {
            var message = JSON.parse(e.data.text());
            var title = message.Title;
            var options = message.Options;

            if (!title)
                title = '';

            e.waitUntil(
                self.registration.showNotification(title, options)
            );
        });
    }

    init();
}

appSw = new appServiceWorker;

if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        appSw.register();
    });
}

self.addEventListener('install', (e) => {
    e.waitUntil(appSw.onInstall());

    self.skipWaiting();
});

self.addEventListener('activate', (e) => {
    e.waitUntil(appSw.onActivate());
});


