@inherits LayoutComponentBase
@implements IDisposable
@inject ServiceLivresApi Api
@inject EtatReseau Reseau

@* Mise en page pensée mobile d'abord : un bandeau, une colonne, rien à gauche.
   Le PC hérite de la même colonne, simplement centrée et limitée en largeur. *@
<header class="bandeau">
    <a class="marque" href="">
        <img src="logo-bandeau.svg" alt="" class="marque-logo" />
        MaBibli
    </a>

    @if (!Reseau.EnLigne)
    {
        @* Une pastille dans le bandeau, visible sur tous les écrans : l'état du réseau change
           l'usage de l'application, il ne doit pas se découvrir au premier clic qui échoue. *@
        <span class="pastille-hors-ligne" title="@EtatReseau.MotifHorsLigne">Hors ligne</span>
    }

    @if (_utilisateur?.Identifiant is not null)
    {
        <span class="utilisateur" title="@(_utilisateur.Simule ? "Utilisateur simulé (développement)" : "Connecté via le portail YunoHost")">
            @_utilisateur.Affichage@(_utilisateur.Simule ? " (dev)" : "")
        </span>
    }
</header>

@if (!Reseau.EnLigne)
{
    @*
        Dire d'où viennent les données et de quand elles datent. Sans cette phrase, une
        bibliothèque affichée hors-ligne est indiscernable d'une bibliothèque à jour — et un
        livre ajouté depuis un autre appareil manquerait sans explication.
    *@
    <p class="bandeau-reseau" role="status">
        <strong>Hors ligne.</strong>
        @(Reseau.DerniereSynchro is { } synchro
            ? $" Données enregistrées {Quand(synchro)}. "
            : " Aucune donnée n'a encore pu être enregistrée sur cet appareil. ")
        Consultation et recherche fonctionnent ; les modifications sont impossibles.
    </p>
}

<main class="contenu">
    @Body
</main>

@*
    Navigation permanente, en bas de l'écran : six onglets, toujours au même endroit.
    Elle remplace les listes de liens que chaque page portait dans sa barre d'actions — cinq
    boutons y passaient sur deux ou trois lignes sur un téléphone, et l'entrée « Envies » ne
    figurait pas partout. Les barres d'actions restantes ne portent plus que des ACTIONS.

    ⚠️ Le pouce atteint le bas de l'écran, pas le haut : c'est ce qui justifie le bas plutôt
    qu'un rang d'onglets sous le bandeau. Les actions de page se placent juste au-dessus
    (variable --mb-onglets-hauteur, partagée avec .actions-flottantes).

    Les onglets restent actifs hors-ligne : les six écrans se consultent depuis leurs
    instantanés. Ce sont les écritures qui se désactivent, pas la navigation.
*@
<nav class="onglets" aria-label="Navigation principale">
    <NavLink class="onglet" href="" Match="NavLinkMatch.All">Catalogue</NavLink>
    <NavLink class="onglet" href="auteurs">Auteurs</NavLink>
    <NavLink class="onglet" href="series">Séries</NavLink>
    <NavLink class="onglet" href="revues">Revues</NavLink>
    <NavLink class="onglet" href="prets">Prêts</NavLink>
    <NavLink class="onglet" href="souhaits">Envies</NavLink>
</nav>

@code {
    private UtilisateurCourant? _utilisateur;
    private bool _etaitEnLigne = true;
    private bool _synchroEnCours;

    protected override async Task OnInitializedAsync()
    {
        Reseau.Change += SurChangementReseau;
        Reseau.SynchroChange += SurSynchro;

        // Écoute des bascules online/offline avant tout appel : un démarrage hors-ligne doit
        // aller directement au cache, sans attendre l'échec d'une requête.
        await Reseau.DemarrerAsync();
        _etaitEnLigne = Reseau.EnLigne;

        _utilisateur = await Api.ObtenirUtilisateurAsync();

        // Rafraîchit tout le fonds, pas seulement l'écran ouvert : c'est ce qui rend la
        // bibliothèque entière consultable et cherchable après la coupure.
        await SynchroniserAsync();
    }

    /// <summary>
    /// Au retour du réseau, on recharge : la bibliothèque a pu changer depuis un autre appareil,
    /// et les actions d'écriture redeviennent disponibles dans la foulée.
    /// </summary>
    private void SurChangementReseau()
    {
        var revenu = Reseau.EnLigne && !_etaitEnLigne;
        _etaitEnLigne = Reseau.EnLigne;

        _ = InvokeAsync(async () =>
        {
            StateHasChanged();

            if (revenu)
            {
                _utilisateur = await Api.ObtenirUtilisateurAsync();
                await SynchroniserAsync();
                StateHasChanged();
            }
        });
    }

    private async Task SynchroniserAsync()
    {
        if (_synchroEnCours)
        {
            return;
        }

        _synchroEnCours = true;

        try
        {
            await Api.SynchroniserAsync();
        }
        finally
        {
            _synchroEnCours = false;
        }
    }

    /// <summary>Date de synchronisation en clair : l'heure suffit le jour même.</summary>
    private static string Quand(DateTimeOffset instant)
    {
        var local = instant.ToLocalTime();

        return local.Date == DateTimeOffset.Now.Date
            ? $"aujourd'hui à {local:HH:mm}"
            : $"le {local:dd/MM/yyyy} à {local:HH:mm}";
    }

    /// <summary>La date affichée vient de changer : rien à recharger, juste à redessiner.</summary>
    private void SurSynchro() => _ = InvokeAsync(StateHasChanged);

    public void Dispose()
    {
        Reseau.Change -= SurChangementReseau;
        Reseau.SynchroChange -= SurSynchro;
    }
}
