using System.Text.Json;
using MaBibli.Api.Services.Isbn;
using MaBibli.Shared.Dtos;

namespace MaBibli.Tests;

/// <summary>
/// Parsing de réponses OpenLibrary réelles.
/// </summary>
public class OpenLibraryMapperTests
{
    private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web);

    private static T Charger<T>(string fixture) =>
        JsonSerializer.Deserialize<T>(Fixture.Lire(fixture), Json)!;

    [Fact]
    public void Ledition_ne_donne_quune_reference_dauteur_pas_un_nom()
    {
        // C'est exactement le bug de BookLogr : sans second appel, l'auteur reste vide.
        var edition = Charger<OpenLibraryEdition>("ol-isbn-9782070612758.json");

        Assert.Equal("Le Petit Prince", edition.Title);
        var cle = Assert.Single(OpenLibraryMapper.ClesAuteurs(edition));
        Assert.Equal("/authors/OL31901A", cle);

        // Le nom n'arrive qu'au second appel, sur /authors/{id}.json.
        var auteur = Charger<OpenLibraryAuthor>("ol-author-OL31901A.json");
        Assert.Equal("Antoine de Saint-Exupéry", OpenLibraryMapper.Nom(auteur));
    }

    [Fact]
    public void Petit_Prince_candidat_complet()
    {
        var edition = Charger<OpenLibraryEdition>("ol-isbn-9782070612758.json");
        var auteur = OpenLibraryMapper.Nom(Charger<OpenLibraryAuthor>("ol-author-OL31901A.json"))!;

        var c = OpenLibraryMapper.VersCandidat(edition, [auteur], "9782070612758", "https://couverture")!;

        Assert.Equal("Le Petit Prince", c.Titre);
        Assert.Equal("Antoine de Saint-Exupéry", c.Auteur);
        Assert.Equal("Editions Gallimard", c.Editeur);
        Assert.Equal("March 2007", c.Annee);
        Assert.Equal("fre", c.Langue);
        Assert.Equal(SourceMetadonnees.OpenLibrary, c.Source);
        Assert.Equal("/books/OL9567312M", c.IdentifiantSource);
        Assert.Equal("https://couverture", c.CoverUrl);
    }

    [Fact]
    public void Germinal_chez_OpenLibrary()
    {
        var edition = Charger<OpenLibraryEdition>("ol-isbn-9782253004226.json");
        var auteur = OpenLibraryMapper.Nom(Charger<OpenLibraryAuthor>("ol-author-OL32772A.json"))!;

        var c = OpenLibraryMapper.VersCandidat(edition, [auteur], "9782253004226", null)!;

        Assert.Equal("Germinal", c.Titre);
        Assert.Equal("Émile Zola", c.Auteur);
        // Les crochets de la notice MARC (« [Librairie Générale Française] ») sont retirés.
        Assert.Equal("Librairie Générale Française", c.Editeur);
        Assert.Equal("1983", c.Annee);
    }

    [Fact]
    public void Introduction_to_Algorithms_na_pas_dauteur_sur_ledition_seulement_sur_loeuvre()
    {
        // Cas réel : le champ `authors` de l'édition est totalement absent.
        // Sans repli sur l'œuvre, l'auteur resterait vide alors que le livre en a quatre.
        var edition = Charger<OpenLibraryEdition>("ol-isbn-9780262033848.json");
        Assert.Empty(OpenLibraryMapper.ClesAuteurs(edition));
        Assert.Equal("/works/OL4781294W", OpenLibraryMapper.CleOeuvre(edition));

        var oeuvre = Charger<OpenLibraryWork>("ol-work-OL4781294W.json");
        var cles = OpenLibraryMapper.ClesAuteurs(oeuvre);
        Assert.Equal(4, cles.Count);

        var noms = cles
            .Select(c => Charger<OpenLibraryAuthor>($"ol-author-{c.Split('/').Last()}.json"))
            .Select(a => OpenLibraryMapper.Nom(a)!)
            .ToList();

        var candidat = OpenLibraryMapper.VersCandidat(edition, noms, "9780262033848", null)!;
        Assert.Equal("Introduction to Algorithms", candidat.Titre);
        // Les quatre auteurs restent quatre entrées distinctes : les recoller en une chaîne
        // rendrait impossible de les distinguer d'un « Zola, Émile » à la virgule près.
        Assert.Equal(
            ["Thomas H. Cormen", "Charles E. Leiserson", "Ronald L. Rivest", "Clifford Stein"],
            candidat.Auteurs);
        Assert.Equal("The MIT Press", candidat.Editeur);
        Assert.Equal("2009", candidat.Annee);
    }

    [Fact]
    public void Sans_aucun_auteur_resolvable_on_retombe_sur_by_statement()
    {
        var edition = Charger<OpenLibraryEdition>("ol-isbn-9780262033848.json");

        var c = OpenLibraryMapper.VersCandidat(edition, [], "9780262033848", null)!;

        Assert.Equal("Thomas H. Cormen", c.Auteur);
    }

    [Fact]
    public void Edition_sans_titre_ne_produit_aucun_candidat()
    {
        var edition = new OpenLibraryEdition { Key = "/books/OL1M" };
        Assert.Null(OpenLibraryMapper.VersCandidat(edition, [], "9782253004226", null));
    }
}
