// Enregistrement du service worker, application automatique au démarrage, bandeau en secours.
//
// Pourquoi ce fichier existe (et pourquoi il n'est pas qu'une ligne `register(...)`) :
//
// 1. Les empreintes des assets WASM sont DÉSACTIVÉES (voir CLAUDE.md). `blazor.webassembly.js`
//    et `dotnet.js` portent donc des noms stables, et c'est le service worker — lui seul — qui
//    empêche de servir éternellement une version périmée. Le mécanisme de Blazor fonctionne,
//    mais il est silencieux et différé : le nouveau worker attend que TOUS les onglets de
//    l'application soient fermés. Sur mobile, un onglet oublié fige la mise à jour sans que
//    personne comprenne pourquoi.
//
// 2. `navigator.serviceWorker` n'existe pas en contexte non sécurisé (http sur une IP locale).
//    L'appeler sans vérification lève une TypeError qui casse le script — et fait croire à un
//    défaut de la PWA alors que c'est le contexte qui n'est pas éligible.
//
// ⚠️ Le clic n'est plus obligatoire (décidé le 2026-08-20, après un blocage constaté sur
// l'application installée sur téléphone). CLAUDE.md actait « jamais tout seul » pour ne pas
// recharger sous une saisie en cours ; la raison reste valable, mais elle ne vaut que pour une
// session déjà entamée. Voir FENETRE_DEMARRAGE ci-dessous.

(function () {
    'use strict';

    if (!('serviceWorker' in navigator)) {
        // Cas normal en http sur une IP de réseau local : rien à signaler à l'utilisateur,
        // l'application fonctionne, elle n'est simplement pas installable ni hors-ligne.
        console.info('Service worker indisponible (contexte non sécurisé ou navigateur sans support).');
        return;
    }

    // Fenêtre pendant laquelle une nouvelle version s'applique TOUTE SEULE, sans rien demander.
    // Au-delà, l'utilisateur est en train de faire quelque chose (une fiche à moitié saisie, un
    // prêt en cours d'enregistrement) : on repasse par le bandeau, pour ne pas lui arracher son
    // travail. Ouvrir l'application depuis l'écran d'accueil du téléphone tombe toujours dans
    // cette fenêtre — c'est exactement le cas qui ne se mettait plus à jour.
    var FENETRE_DEMARRAGE = 10000;

    // Si la reprise en main n'a pas lieu, on recharge quand même : le pire scénario est de
    // laisser l'utilisateur devant un bouton grisé qui ne fait rien.
    var DELAI_REPRISE = 5000;

    // Une seule reprise forcée par session : si la nouvelle version n'arrive pas à s'activer,
    // recharger en boucle transformerait une mise à jour ratée en application inutilisable.
    var CLE_FORCE = 'mb-maj-forcee';

    var demandee = false;
    var recharge = false;

    function recharger() {
        if (recharge) return;
        recharge = true;
        window.location.reload();
    }

    function appliquer(enAttente) {
        demandee = true;
        // Le worker en attente prend la main sans qu'on ait à fermer tous les onglets.
        enAttente.postMessage({ type: 'SKIP_WAITING' });

        // Filet. `controllerchange` devrait suivre ; s'il ne vient pas (worker en attente issu
        // d'une version antérieure au gestionnaire SKIP_WAITING, reprise en main qui échoue),
        // rien ne se passerait du tout et le bouton resterait grisé pour toujours.
        window.setTimeout(function () {
            if (recharge) return;
            var dejaForcee = false;
            try {
                dejaForcee = window.sessionStorage.getItem(CLE_FORCE) === '1';
                window.sessionStorage.setItem(CLE_FORCE, '1');
            } catch (e) {
                // Navigation privée ou stockage refusé : on préfère ne pas forcer plutôt que
                // risquer une boucle de rechargement qu'on ne saurait plus arrêter.
                dejaForcee = true;
            }
            if (!dejaForcee) recharger();
        }, DELAI_REPRISE);
    }

    function proposerLaMiseAJour(enAttente) {
        if (document.getElementById('mb-maj')) return;

        var barre = document.createElement('div');
        barre.id = 'mb-maj';
        barre.setAttribute('role', 'status');
        barre.textContent = 'Une nouvelle version de MaBibli est disponible. ';

        var bouton = document.createElement('button');
        bouton.type = 'button';
        bouton.textContent = 'Mettre à jour';
        bouton.addEventListener('click', function () {
            bouton.disabled = true;
            bouton.textContent = 'Mise à jour…';
            appliquer(enAttente);
        });

        barre.appendChild(bouton);
        document.body.appendChild(barre);
    }

    // Au démarrage : on applique sans demander. Plus tard : on propose.
    function traiter(enAttente) {
        if (performance.now() < FENETRE_DEMARRAGE) {
            appliquer(enAttente);
        } else {
            proposerLaMiseAJour(enAttente);
        }
    }

    // ⚠️ Chemin ABSOLU, et scope explicite. `register('service-worker.js')` se résout contre
    // l'URL du DOCUMENT et non contre <base href="/"> : ouvrir l'application sur une route
    // profonde (/souhaits, /livres/3) visait /souhaits/service-worker.js, que le serveur ne sert
    // pas — l'enregistrement échouait alors silencieusement, et avec lui tout le hors-ligne.
    navigator.serviceWorker.register('/service-worker.js', { scope: '/', updateViaCache: 'none' })
        .then(function (enregistrement) {
            // Un worker déjà installé attendait peut-être depuis la visite précédente.
            if (enregistrement.waiting && navigator.serviceWorker.controller) {
                traiter(enregistrement.waiting);
            }

            enregistrement.addEventListener('updatefound', function () {
                var nouveau = enregistrement.installing;
                if (!nouveau) return;

                nouveau.addEventListener('statechange', function () {
                    // `controller` non nul = ce n'est pas la première installation, donc il y a
                    // bien une version précédente à remplacer.
                    if (nouveau.state === 'installed' && navigator.serviceWorker.controller) {
                        traiter(nouveau);
                    }
                });
            });

            // Vérification explicite à chaque chargement : ne pas dépendre du seul rythme
            // interne du navigateur pour découvrir une version plus récente.
            enregistrement.update().catch(function () { /* hors-ligne : sans objet */ });
        })
        .catch(function (erreur) {
            // Ne jamais laisser cet échec passer inaperçu : sans service worker, l'application
            // ne démarre pas hors-ligne, et le cache IndexedDB ne sert alors à rien.
            console.error("Échec de l'enregistrement du service worker :", erreur);
        });

    // Le rechargement n'a lieu que si la mise à jour a été demandée — automatiquement ou par un
    // clic. Un changement de contrôleur survient aussi à la toute première installation, et
    // recharger la page à ce moment-là serait un clignotement inexplicable.
    navigator.serviceWorker.addEventListener('controllerchange', function () {
        if (demandee) recharger();
    });
})();
