using MaBibli.Api.Services.Isbn;

namespace MaBibli.Tests;

public class NettoyageIsbdTests
{
    [Theory]
    [InlineData("Germinal / Émile Zola ; préface d'Armand Lanoux", "Germinal")]
    [InlineData("Germinal / Émile Zola ; préf., dossier et notes par Colette Becker", "Germinal")]
    [InlineData("Le Horla / Guy de Maupassant", "Le Horla")]
    public void Titre_coupe_a_la_mention_de_responsabilite(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Titre(brut));

    [Theory]
    [InlineData("Germinal", "Germinal")]
    [InlineData("Le Petit Prince", "Le Petit Prince")]
    [InlineData("Introduction to Algorithms", "Introduction to Algorithms")]
    // Le sous-titre ISBD (« : ») n'est pas de la ponctuation à retirer : on le garde.
    [InlineData("Voyage au bout de la nuit : roman", "Voyage au bout de la nuit : roman")]
    // Un « / » sans espaces autour appartient au titre, il ne doit pas servir de coupure.
    [InlineData("Entrée/sortie", "Entrée/sortie")]
    public void Titre_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Titre(brut));

    /// <summary>
    /// Cas réel mesuré sur l'ISBN <c>9782749942636</c> : la BnF recolle le nom de l'auteur en
    /// fin de titre <b>sans</b> le séparateur ISBD, ce que <see cref="NettoyageIsbd.Titre"/> ne
    /// peut donc pas voir.
    /// </summary>
    [Fact]
    public void Titre_retire_le_nom_de_lauteur_colle_en_fin()
    {
        const string brut = "Le plus grand défi de l'histoire de l'humanité : face à la "
                            + "catastrophe écologique et sociale (Nouvelle éd. augmentée) Aurélien Barrau";

        var titre = NettoyageIsbd.RetirerAuteurEnFin(brut, ["Aurélien Barrau"]);

        Assert.Equal(
            "Le plus grand défi de l'histoire de l'humanité : face à la catastrophe écologique "
            + "et sociale (Nouvelle éd. augmentée)",
            titre);
    }

    [Theory]
    // Contre-exemple central : le nom est bien là, mais pas en fin de chaîne. On n'y touche pas.
    [InlineData("Lettre à Émile Zola", "Guy de Maupassant")]
    [InlineData("Émile Zola et son temps", "Émile Zola")]
    // Le titre EST le nom de l'auteur (biographie, recueil) : le retirer ne laisserait rien.
    [InlineData("Aurélien Barrau", "Aurélien Barrau")]
    // Fin de mot fortuite : « Zola » ne doit pas être découpé dans « Gorgonzola ».
    [InlineData("Éloge du gorgonzola", "Zola")]
    // Auteur inconnu du titre.
    [InlineData("Germinal", "Émile Zola")]
    public void Titre_ne_mutile_pas_un_nom_legitime(string titre, string auteur)
        => Assert.Equal(titre, NettoyageIsbd.RetirerAuteurEnFin(titre, [auteur]));

    [Fact]
    public void Titre_tolere_une_difference_daccent_ou_de_casse_sur_le_nom()
        => Assert.Equal(
            "Le grand défi",
            NettoyageIsbd.RetirerAuteurEnFin("Le grand défi AURELIEN BARRAU", ["Aurélien Barrau"]));

    [Fact]
    public void Titre_sans_auteur_connu_reste_intact()
    {
        Assert.Equal("Germinal", NettoyageIsbd.RetirerAuteurEnFin("Germinal", []));
        Assert.Equal("Germinal", NettoyageIsbd.RetirerAuteurEnFin("Germinal", [null, "  "]));
        Assert.Null(NettoyageIsbd.RetirerAuteurEnFin(null, ["Émile Zola"]));
    }

    [Theory]
    [InlineData("Zola, Émile (1840-1902). Auteur du texte", "Émile Zola")]
    [InlineData("Saint-Exupéry, Antoine de (1900-1944). Auteur du texte", "Antoine de Saint-Exupéry")]
    [InlineData("Maupassant, Guy de (1850-1893). Auteur du texte", "Guy de Maupassant")]
    [InlineData("Becker, Colette (1932-....). Éditeur scientifique", "Colette Becker")]
    [InlineData("Zola, Émile (1840-1902)", "Émile Zola")]
    [InlineData("Zola, Émile. Auteur du texte", "Émile Zola")]
    public void Auteur_retire_dates_et_role_puis_inverse(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));

    [Theory]
    [InlineData("Émile Zola", "Émile Zola")]
    [InlineData("Antoine de Saint-Exupéry", "Antoine de Saint-Exupéry")]
    [InlineData("Molière", "Molière")]
    public void Auteur_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));

    [Theory]
    // Contre-exemples : le nom se termine légitimement par une initiale, il n'y a pas de rôle
    // à retirer — couper au point amputerait le prénom.
    [InlineData("Cormen, Thomas H.", "Thomas H. Cormen")]
    [InlineData("Tolkien, J. R. R.", "J. R. R. Tolkien")]
    // Cas réel : le rôle suit une initiale. Protéger le point de l'initiale ne doit pas
    // protéger le rôle — sinon on obtient « Thomas H. Auteur du texte Cormen ».
    [InlineData("Cormen, Thomas H. Auteur du texte", "Thomas H. Cormen")]
    [InlineData("Tolkien, J. R. R. (1892-1973). Auteur du texte", "J. R. R. Tolkien")]
    public void Auteur_distingue_une_initiale_d_un_role(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));

    [Theory]
    [InlineData("le Livre de poche (Paris)", "le Livre de poche")]
    [InlineData("Librairie générale française (Paris)", "Librairie générale française")]
    [InlineData("Gallimard (Paris)", "Gallimard")]
    public void Editeur_retire_la_ville_finale(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Editeur(brut));

    [Theory]
    [InlineData("Gallimard", "Gallimard")]
    [InlineData("The MIT Press", "The MIT Press")]
    // Parenthèses en milieu de chaîne : ce n'est pas la ville, on n'y touche pas.
    [InlineData("Presses (universitaires) de France", "Presses (universitaires) de France")]
    public void Editeur_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
        => Assert.Equal(attendu, NettoyageIsbd.Editeur(brut));

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void Champs_vides_donnent_null(string? brut)
    {
        Assert.Null(NettoyageIsbd.Titre(brut));
        Assert.Null(NettoyageIsbd.Auteur(brut));
        Assert.Null(NettoyageIsbd.Editeur(brut));
    }
}
