function installServiceWorker() {
    if ("serviceWorker" in navigator) {
        navigator.serviceWorker.register("/service-worker.js", {
            scope: "/",
        }).then(function (registration) {
            if (registration.installing) {
                console.log("Service worker installing");
            } else if (registration.waiting) {
                console.log("Service worker installed");
            } else if (registration.active) {
                console.log("Service worker active");
            }
            registration.update();
        }).catch(function (error) {
            console.error('Registration failed with ' + error);
        });
    }
}

function uninstallServiceWorker() {
    if ("serviceWorker" in navigator) {
        navigator.serviceWorker.getRegistrations().then(function (registrations) {
            for (var i = 0; i < registrations.length; i++) {
                var registration = registrations[i];
                registration.unregister()
            }
            if (registrations.length > 0) {
                window.location.reload();
            }
        })
    }
    if ('caches' in window) {
        caches.keys().then(function (keyList) {
            return Promise.all(keyList.map(function (key) {
                return caches.delete(key);
            }));
        })
    }
}

function functionNameFromEventName(eventName) {
    return 'on' + eventName.substring(0, 1).toUpperCase() + eventName.substring(1);
}

function lumicastSdk() {
    var sdk = {};

    var initialized = false;
    var callbacks = {};
    var eventNames = [
        'data', 'play', 'ready', 'load', 'reset', 'fonts', 'metadata'
    ];

    sdk.init = function (options) {
        if (initialized) {
            throw new Error('SDK has already been initialized.');
        }

        if (options) {
            if (options.serviceWorker) {
                installServiceWorker();
            } else {
                uninstallServiceWorker();
            }
        }

        initialized = true;
    }

    sdk.markPlaying = function () {
        window.parent.postMessage({ event: 'app:playing' }, '*');
    }

    sdk.markReady = function () {
        window.parent.postMessage({ event: 'app:ready' }, '*');
    }

    sdk.reportError = function (message) {
        console.error(message);

        window.parent.postMessage({ event: 'app:error', message: message }, '*');
    }

    sdk.on = function (eventName, callback) {
        if (!initialized) {
            throw new Error('SDK has not been initialized with #init(options).');
        }

        if (!eventNames.includes(eventName)) {
            throw new Error('Event ' + eventName + ' is not supported.');
        }

        callbacks[eventName] = callback;
    }

    for (var i = 0; i < eventNames.length; i++) {
        (function() {
            var eventName = eventNames[i];
            var functionName = functionNameFromEventName(eventName);
    
            sdk[functionName] = function (callback) {
                if (!initialized) {
                    throw new Error('SDK has not been initialized with #init(options).');
                }
                if (typeof callback !== 'function') {
                    throw new Error('Supplied callback in ' + functionName + ' is not a function.');
                }
                callbacks[eventName] = callback;
            }
        })();
    }

    var optionalEvents = ['fonts', 'reset']

    window.addEventListener('message', function (event) {
        var eventName = event.data.event;
        if (!eventName) return;

        if (eventName.startsWith('app:')) {
            eventName = eventName.substring(4);

            var called = false;
            var data = event.data;
            if (eventName === 'load') {
                data = data.config;
            } else if (eventName === 'data') {
                data = data.dataSources;
            } else if(eventName === 'metadata') {
                data = data.metadata;
            } else if(eventName === 'fonts') {
                for (var i = 0; i < data.fonts.length; i++) {
                    var font = data.fonts[i];
                    var fontFace = new FontFace(font.name, font.src, font.options);
            
                    document.fonts.add(fontFace);
            
                    fontFace.load();
                }
                console.log('Loaded ' + data.fonts.length + ' fonts.');
            }

            var call = function() {
                if (callbacks[eventName]) {
                    called = true;
                    callbacks[eventName](data);
                }
            };

            call();

            if (!called) {
                if (!optionalEvents.includes(eventName)) {
                    sdk.reportError('Received ' + eventName + ' but was not consumed by app.');
                }

                setTimeout(function() {
                    call();
                }, 1000);
            }
        }
    });

    return sdk;
}

console.log('Registering Lumicast SDK.');
window.lumicastSdk = lumicastSdk();
console.log('Lumicast SDK ready.');
