@page "/series"
@inject ServiceLivresApi Api
@inject EtatReseau Reseau
@implements IDisposable

<PageTitle>MaBibli — séries</PageTitle>

<h1 class="titre-page">Séries</h1>

<p class="message-discret">
    Sagas, cycles et trilogies, dans leur ordre de <strong>lecture</strong> — qui n'est pas
    toujours celui de publication. Les séries sont communes au foyer, comme le catalogue.
</p>

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

@* Créer une série depuis la liste : c'est le seul endroit d'où l'on part, et un écran de plus
   pour un unique champ ne se justifierait pas. *@
<div class="barre-recherche">
    <input class="champ-saisie" type="text" placeholder="Nom d'une nouvelle série…"
           @bind="_nouveau" @bind:event="oninput" @onkeydown="SurTouche"
           aria-label="Nom de la nouvelle série" autocomplete="off" />
</div>

<div class="actions-formulaire">
    <button type="button" class="bouton bouton-principal"
            disabled="@(_enCours || !Reseau.EnLigne || string.IsNullOrWhiteSpace(_nouveau))"
            title="@MotifBlocage"
            @onclick="CreerAsync">
        Créer la série
    </button>
</div>

@if (_series is null)
{
    <p class="message-discret" role="status">Chargement…</p>
}
else if (_series.Count == 0)
{
    <p class="message-discret">
        Aucune série pour l'instant. Créez-en une, puis ajoutez-y vos livres et les tomes
        qui vous manquent : c'est ce qui permet de voir les trous.
    </p>
}
else
{
    <ul class="liste-series">
        @foreach (var serie in Racines)
        {
            <ArbreSerie Serie="serie" Toutes="_series" Livres="_livres"
                        Totaux="_totaux" Deplies="_deplies" />
        }
    </ul>
}

@code {
    private IReadOnlyList<SerieDto>? _series;
    private IReadOnlyList<LivreDto> _livres = [];
    private IReadOnlyDictionary<int, (int Possedes, int Total)> _totaux =
        new Dictionary<int, (int, int)>();
    private readonly HashSet<int> _deplies = [];
    private string _nouveau = string.Empty;
    private bool _enCours;
    private string? _erreur;

    private string? MotifBlocage => Reseau.EnLigne ? null : EtatReseau.MotifHorsLigne;

    /// <summary>Séries de premier niveau. Celles rangées dans un cycle s'affichent sous lui.</summary>
    private IEnumerable<SerieDto> Racines =>
        _series?.Where(s => s.SerieParenteId is null) ?? [];

    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()
    {
        _series = await Api.ListerSeriesAsync();
        _livres = await Api.ListerAsync(new CritereLivres());
        _totaux = TotauxSeries.Calculer(_series);
    }

    private async Task SurTouche(KeyboardEventArgs e)
    {
        if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(_nouveau) && Reseau.EnLigne)
        {
            await CreerAsync();
        }
    }

    private async Task CreerAsync()
    {
        _enCours = true;
        _erreur = null;

        var resultat = await Api.CreerSerieAsync(new EnregistrementSerie { Titre = _nouveau });

        _enCours = false;

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

        _nouveau = string.Empty;
        await ChargerAsync();
    }
}
