@page "/prets"
@using MaBibli.Shared.Textes
@inject ServiceLivresApi Api
@inject EtatReseau Reseau
@implements IDisposable

@*
    Ce qui n'est pas à la maison. C'est l'usage principal des prêts : savoir d'un coup d'œil
    quels livres sont dehors, et chez qui.

    La liste est commune à tout le foyer, sans filtre par utilisateur : n'importe qui doit
    pouvoir constater qu'un livre manque, et noter son retour quand il le récupère.
*@

<PageTitle>MaBibli — prêts en cours</PageTitle>

<h1 class="titre-page">Prêts en cours</h1>

@if (_erreur is not null)
{
    <p class="message-erreur" role="alert">@_erreur</p>
}

@if (_prets is null)
{
    <p class="message-discret">Chargement…</p>
}
else if (_prets.Count == 0)
{
    @* Hors-ligne, une liste vide peut aussi vouloir dire « rien n'a encore été enregistré ici » :
       on ne l'affirme comme un fait que si l'information vient bien d'une synchronisation. *@
    <p class="message-discret">
        @(Reseau.EnLigne || Reseau.DerniereSynchro is not null
            ? "Tous les livres sont à la maison."
            : "Aucune donnée enregistrée sur cet appareil : impossible de dire ce qui est prêté.")
    </p>
}
else
{
    <p class="compteur">@_prets.Count livre@(_prets.Count > 1 ? "s" : "") dehors</p>

    @* Filtre en mémoire : la liste des prêts en cours est courte, une forme normalisée en
       base serait disproportionnée pour ce seul besoin (voir IDEES.md, lot G). La recherche
       reste insensible aux accents et à la casse, comme partout ailleurs dans l'application. *@
    @if (_prets.Count > 1)
    {
        <div class="barre-recherche">
            <input class="champ-saisie" type="search" placeholder="Filtrer par emprunteur…"
                   value="@_recherche" @oninput="SurRecherche" aria-label="Filtrer par emprunteur" />
        </div>
    }

    @if (PretsAffiches().Count == 0)
    {
        <p class="message-discret">Aucun prêt ne correspond à « @_recherche ».</p>
    }

    <ul class="liste-livres">
        @foreach (var pret in PretsAffiches())
        {
            <li class="carte-livre" @key="pret.Id">
                <Couverture Url="@pret.LivreCoverUrl" Titre="@pret.LivreTitre"
                            Classe="couverture-petite" Agrandissable="true" />

                <div class="carte-corps">
                    <a class="carte-titre" href="@($"livres/{pret.LivreId}")">@pret.LivreTitre</a>

                    @if (!string.IsNullOrWhiteSpace(pret.LivreAuteurs))
                    {
                        <p class="carte-auteur">@pret.LivreAuteurs</p>
                    }

                    <p class="carte-details">
                        <span class="etiquette etiquette-prete">@pret.Emprunteur</span>
                        <span>depuis le @pret.DatePret.ToLocalTime().ToString("dd/MM/yyyy")</span>
                        <span class="pret-duree">@PretsLivre.Duree(pret.JoursEcoules)</span>
                    </p>

                    @* Le retour se note ici : on récupère un livre, on ouvre la liste des prêts,
                       on coche. Passer par la fiche du livre serait un détour. *@
                    <button type="button" class="bouton bouton-discret bouton-compact"
                            disabled="@(_enCours == pret.Id || !Reseau.EnLigne)"
                            title="@(Reseau.EnLigne ? null : EtatReseau.MotifHorsLigne)"
                            @onclick="() => RendreAsync(pret)">
                        @(_enCours == pret.Id ? "Enregistrement…" : "Rendu")
                    </button>
                </div>
            </li>
        }
    </ul>
}

@code {
    private IReadOnlyList<PretDto>? _prets;
    private string? _erreur;
    private int? _enCours;
    private string _recherche = string.Empty;

    private void SurRecherche(ChangeEventArgs e) => _recherche = e.Value?.ToString() ?? string.Empty;

    private IReadOnlyList<PretDto> PretsAffiches()
    {
        if (_prets is null)
        {
            return [];
        }

        var terme = NormalisationTexte.Normaliser(_recherche);
        return terme.Length == 0
            ? _prets
            : _prets.Where(p => NormalisationTexte.Normaliser(p.Emprunteur).Contains(terme)).ToList();
    }

    protected override void OnInitialized() => Reseau.Change += SurChangementReseau;

    private void SurChangementReseau() => _ = InvokeAsync(async () =>
    {
        await ChargerAsync();
        StateHasChanged();
    });

    public void Dispose() => Reseau.Change -= SurChangementReseau;

    protected override Task OnInitializedAsync() => ChargerAsync();

    private async Task ChargerAsync()
    {
        _erreur = null;

        try
        {
            _prets = await Api.ListerPretsEnCoursAsync();
        }
        catch (Exception ex)
        {
            _erreur = $"Impossible de charger les prêts : {ex.Message}";
            _prets = [];
        }
    }

    private async Task RendreAsync(PretDto pret)
    {
        _enCours = pret.Id;
        var resultat = await Api.RendreAsync(pret.Id);
        _enCours = null;

        if (!resultat.EstOk)
        {
            _erreur = resultat.Erreur;
        }

        // Rechargement complet plutôt que retrait local : quelqu'un d'autre du foyer a pu rendre
        // ou prêter un livre entre-temps, et cette vue est justement celle qu'on garde ouverte.
        await ChargerAsync();
    }
}
