(function () {
    const config = window.CCW_WEB_APP_CONFIG || {};
    const serviceWorkerUrl = typeof config.serviceWorkerUrl === 'string' ? config.serviceWorkerUrl : '';
    const scope = typeof config.scope === 'string' && config.scope !== '' ? config.scope : '/';
    const canUseServiceWorker = 'serviceWorker' in navigator && !!serviceWorkerUrl;
    const storageKeyDismissed = 'ccwPwaInstallDismissed';
    const configLabels = config.labels || {};
    const labels = {
        updateTitle: configLabels.updateTitle || 'A new version is ready',
        updateMessage: configLabels.updateMessage || 'Refresh to load the latest version of the app',
        updateApply: configLabels.updateApply || 'Refresh now',
        updateDismiss: configLabels.updateDismiss || 'Later',
        installTitle: configLabels.installTitle || 'Install CCW on your home screen',
        installMessage: configLabels.installMessage || 'Launch it like an app for faster access and a cleaner mobile experience',
        installApply: configLabels.installApply || 'Install app',
        installDismiss: configLabels.installDismiss || 'Later',
        installIosTitle: configLabels.installIosTitle || 'Add CCW to your home screen',
        installIosMessage: configLabels.installIosMessage || 'Open the Share menu in Safari and choose Add to Home Screen',
        installIosButton: configLabels.installIosButton || 'Got it',
        installAndroidTitle: configLabels.installAndroidTitle || 'Install CCW on Android',
        installAndroidMessage: configLabels.installAndroidMessage || 'Open the browser menu and choose Install app or Add to Home screen',
        installAndroidButton: configLabels.installAndroidButton || 'Got it',
        installInsecureTitle: configLabels.installInsecureTitle || 'Install app is limited on this connection',
        installInsecureMessage: configLabels.installInsecureMessage || 'Open this site over HTTPS for one-tap install, or use the browser menu to add it to your home screen',
        installInsecureButton: configLabels.installInsecureButton || 'Got it'
    };

    let pendingWorker = null;
    let deferredInstallPrompt = null;
    let updatePromptElement = null;
    let installPromptElement = null;
    let embeddedInstallPanel = null;
    let embeddedInstallMode = 'install';
    let refreshing = false;

    function isStandaloneMode() {
        return !!(
            (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches)
            || window.navigator.standalone
        );
    }

    function isAndroidDevice() {
        const userAgent = window.navigator.userAgent || '';
        return /Android/i.test(userAgent);
    }

    function isSecureInstallContext() {
        const protocol = window.location.protocol || '';
        const hostname = window.location.hostname || '';
        return window.isSecureContext
            || protocol === 'https:'
            || hostname === 'localhost'
            || hostname === '127.0.0.1'
            || hostname === '[::1]'
            || hostname === '::1';
    }

    function isIosSafariInstallable() {
        const userAgent = window.navigator.userAgent || '';
        const isIosDevice = /iPad|iPhone|iPod/i.test(userAgent);
        const isSafariBrowser = /Safari/i.test(userAgent) && !/CriOS|FxiOS|EdgiOS|OPiOS/i.test(userAgent);
        return isIosDevice && isSafariBrowser && !isStandaloneMode();
    }

    function removeElement(element) {
        if (element && element.parentNode) {
            element.parentNode.removeChild(element);
        }
    }

    function getEmbeddedInstallPanel() {
        if (!embeddedInstallPanel) {
            embeddedInstallPanel = document.querySelector('[data-pwa-install-panel]');
        }

        return embeddedInstallPanel;
    }

    function hideEmbeddedInstallPanel(rememberDismissal) {
        const panel = getEmbeddedInstallPanel();
        if (!panel) {
            return;
        }

        if (rememberDismissal && embeddedInstallMode === 'install') {
            try {
                window.localStorage.setItem(storageKeyDismissed, '1');
            } catch (error) {
                // Ignore storage errors.
            }
        }

        panel.hidden = true;
        panel.classList.add('is-hidden');
    }

    function bindEmbeddedInstallPanel() {
        const panel = getEmbeddedInstallPanel();
        if (!panel || panel.dataset.bound === '1') {
            return;
        }

        panel.dataset.bound = '1';

        const applyButton = panel.querySelector('[data-pwa-install-button]');
        const dismissButton = panel.querySelector('[data-pwa-install-dismiss]');

        if (applyButton) {
            applyButton.addEventListener('click', function () {
                if (embeddedInstallMode === 'ios' || embeddedInstallMode === 'android' || embeddedInstallMode === 'insecure') {
                    hideEmbeddedInstallPanel(false);
                    return;
                }

                if (!deferredInstallPrompt) {
                    return;
                }

                const installEvent = deferredInstallPrompt;
                deferredInstallPrompt = null;
                hideEmbeddedInstallPanel(false);
                installEvent.prompt();
                installEvent.userChoice.finally(function () {
                    maybeShowInstallPrompt();
                });
            });
        }

        if (dismissButton) {
            dismissButton.addEventListener('click', function () {
                hideEmbeddedInstallPanel(embeddedInstallMode === 'install');
            });
        }
    }

    function showEmbeddedInstallPanel(mode) {
        const panel = getEmbeddedInstallPanel();
        if (!panel) {
            return false;
        }

        bindEmbeddedInstallPanel();
        embeddedInstallMode = mode;

        let title = panel.dataset.installTitle || labels.installTitle;
        let message = panel.dataset.installMessage || labels.installMessage;
        let buttonLabel = panel.dataset.installButtonLabel || labels.installApply;

        if (mode === 'ios') {
            title = panel.dataset.iosTitle || labels.installIosTitle;
            message = panel.dataset.iosMessage || labels.installIosMessage;
            buttonLabel = panel.dataset.iosButtonLabel || labels.installIosButton;
        } else if (mode === 'android') {
            title = panel.dataset.androidTitle || labels.installAndroidTitle;
            message = panel.dataset.androidMessage || labels.installAndroidMessage;
            buttonLabel = panel.dataset.androidButtonLabel || labels.installAndroidButton;
        } else if (mode === 'insecure') {
            title = panel.dataset.insecureTitle || labels.installInsecureTitle;
            message = panel.dataset.insecureMessage || labels.installInsecureMessage;
            buttonLabel = panel.dataset.insecureButtonLabel || labels.installInsecureButton;
        }

        const dismissLabel = panel.dataset.dismissLabel || labels.installDismiss;

        const titleTarget = panel.querySelector('[data-pwa-install-title]');
        const messageTarget = panel.querySelector('[data-pwa-install-message]');
        const applyButton = panel.querySelector('[data-pwa-install-button]');
        const dismissButton = panel.querySelector('[data-pwa-install-dismiss]');

        if (titleTarget) {
            titleTarget.textContent = title;
        }

        if (messageTarget) {
            messageTarget.textContent = message;
        }

        if (applyButton) {
            applyButton.textContent = buttonLabel;
        }

        if (dismissButton) {
            dismissButton.textContent = dismissLabel;
        }

        panel.hidden = false;
        panel.classList.remove('is-hidden');
        return true;
    }

    function removeUpdatePrompt() {
        removeElement(updatePromptElement);
        updatePromptElement = null;
    }

    function removeInstallPrompt(rememberDismissal) {
        if (rememberDismissal) {
            try {
                window.localStorage.setItem(storageKeyDismissed, '1');
            } catch (error) {
                // Ignore storage errors.
            }
        }

        hideEmbeddedInstallPanel(false);
        removeElement(installPromptElement);
        installPromptElement = null;
    }

    function buildPrompt(className, title, message, primaryLabel, secondaryLabel) {
        const prompt = document.createElement('div');
        prompt.className = className;
        prompt.innerHTML =
            '<div class="' + className + '-copy">' +
                '<strong>' + title + '</strong>' +
                '<span>' + message + '</span>' +
            '</div>' +
            '<div class="' + className + '-actions">' +
                '<button type="button" class="button button-accent ' + className + '-apply">' + primaryLabel + '</button>' +
                '<button type="button" class="button button-secondary ' + className + '-dismiss">' + secondaryLabel + '</button>' +
            '</div>';

        return prompt;
    }

    function showUpdatePrompt(worker) {
        pendingWorker = worker;
        removeUpdatePrompt();

        const prompt = buildPrompt(
            'pwa-update-prompt',
            labels.updateTitle,
            labels.updateMessage,
            labels.updateApply,
            labels.updateDismiss
        );

        prompt.querySelector('.pwa-update-prompt-apply').addEventListener('click', function () {
            if (pendingWorker) {
                pendingWorker.postMessage({ type: 'SKIP_WAITING' });
            }
        });

        prompt.querySelector('.pwa-update-prompt-dismiss').addEventListener('click', function () {
            removeUpdatePrompt();
        });

        document.body.appendChild(prompt);
        updatePromptElement = prompt;
    }

    function maybeShowInstallPrompt() {
        if (isStandaloneMode()) {
            removeInstallPrompt(false);
            return;
        }

        if (isIosSafariInstallable() && showEmbeddedInstallPanel('ios')) {
            removeElement(installPromptElement);
            installPromptElement = null;
            return;
        }

        if (!deferredInstallPrompt && !isSecureInstallContext() && showEmbeddedInstallPanel('insecure')) {
            removeElement(installPromptElement);
            installPromptElement = null;
            return;
        }

        if (!deferredInstallPrompt && isAndroidDevice() && showEmbeddedInstallPanel('android')) {
            removeElement(installPromptElement);
            installPromptElement = null;
            return;
        }

        try {
            if (window.localStorage.getItem(storageKeyDismissed) === '1') {
                return;
            }
        } catch (error) {
            // Ignore storage errors.
        }

        if (deferredInstallPrompt && showEmbeddedInstallPanel('install')) {
            removeElement(installPromptElement);
            installPromptElement = null;
            return;
        }

        if (!deferredInstallPrompt) {
            return;
        }

        removeInstallPrompt(false);

        const prompt = buildPrompt(
            'pwa-install-prompt',
            labels.installTitle,
            labels.installMessage,
            labels.installApply,
            labels.installDismiss
        );

        prompt.querySelector('.pwa-install-prompt-apply').addEventListener('click', function () {
            if (!deferredInstallPrompt) {
                return;
            }

            const installEvent = deferredInstallPrompt;
            deferredInstallPrompt = null;
            removeInstallPrompt(false);
            installEvent.prompt();
            installEvent.userChoice.finally(function () {
                maybeShowInstallPrompt();
            });
        });

        prompt.querySelector('.pwa-install-prompt-dismiss').addEventListener('click', function () {
            removeInstallPrompt(true);
        });

        document.body.appendChild(prompt);
        installPromptElement = prompt;
    }

    function trackRegistration(registration) {
        if (registration.waiting) {
            showUpdatePrompt(registration.waiting);
        }

        registration.addEventListener('updatefound', function () {
            const newWorker = registration.installing;
            if (!newWorker) {
                return;
            }

            newWorker.addEventListener('statechange', function () {
                if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
                    showUpdatePrompt(newWorker);
                }
            });
        });
    }

    if (canUseServiceWorker) {
        navigator.serviceWorker.addEventListener('controllerchange', function () {
            if (refreshing) {
                return;
            }

            refreshing = true;
            window.location.reload();
        });
    }

    window.addEventListener('beforeinstallprompt', function (event) {
        event.preventDefault();
        deferredInstallPrompt = event;
        maybeShowInstallPrompt();
    });

    window.addEventListener('appinstalled', function () {
        document.documentElement.classList.add('pwa-installed');
        removeInstallPrompt(false);
        removeUpdatePrompt();
        deferredInstallPrompt = null;

        try {
            window.localStorage.removeItem(storageKeyDismissed);
        } catch (error) {
            // Ignore storage errors.
        }
    });

    if (isStandaloneMode()) {
        document.documentElement.classList.add('pwa-standalone');
        removeInstallPrompt(false);
    }

    window.addEventListener('load', function () {
        bindEmbeddedInstallPanel();
        maybeShowInstallPrompt();

        if (canUseServiceWorker) {
            navigator.serviceWorker.register(serviceWorkerUrl, { scope: scope }).then(function (registration) {
                trackRegistration(registration);
                window.setTimeout(function () {
                    registration.update().catch(function () { return null; });
                }, 4000);
            }).catch(function (error) {
                console.warn('PWA service worker registration failed.', error);
                maybeShowInstallPrompt();
            });
        }
    });

    document.addEventListener('visibilitychange', function () {
        if (document.visibilityState === 'visible') {
            maybeShowInstallPrompt();

            if (canUseServiceWorker) {
                navigator.serviceWorker.getRegistration(scope).then(function (registration) {
                    if (registration) {
                        registration.update().catch(function () { return null; });
                    }
                });
            }
        }
    });
})();
