using MaBibli.Shared.Textes;

namespace MaBibli.Tests;

/// <summary>
/// Règles de regroupement des noms d'auteurs.
/// </summary>
/// <remarks>
/// La frontière testée ici est celle que CLAUDE.md pose : <b>ce qui est sûr est fusionné, ce qui
/// est ambigu est proposé</b>. Les tests sont écrits par catégorie plutôt que par cas, pour que
/// l'ajout d'une règle oblige à dire de quel côté de la frontière elle tombe.
/// </remarks>
public class RapprochementAuteursTests
{
    [Theory]
    // Casse et accents.
    [InlineData("Émile Zola", "emile zola")]
    [InlineData("Émile Zola", "EMILE ZOLA")]
    [InlineData("Émile Zola", "Emile Zola")]
    // Ordre inversé, avec ou sans virgule.
    [InlineData("Zola, Émile", "Émile Zola")]
    [InlineData("Zola, Emile", "emile zola")]
    // Initiales abrégées, le reste concordant.
    [InlineData("Peter F. Hamilton", "P.F. Hamilton")]
    [InlineData("Peter F. Hamilton", "P. F. Hamilton")]
    [InlineData("P.F. Hamilton", "P. F. Hamilton")]
    [InlineData("Thomas H. Cormen", "T. H. Cormen")]
    // Combinaison des trois.
    [InlineData("Hamilton, Peter F.", "p f hamilton")]
    // Auteur mononyme.
    [InlineData("Homère", "homere")]
    public void Les_variantes_sures_sont_reconnues(string a, string b)
    {
        Assert.Equal(NiveauRapprochement.Certain, RapprochementAuteurs.Comparer(a, b));
        Assert.Equal(NiveauRapprochement.Certain, RapprochementAuteurs.Comparer(b, a));
    }

    [Theory]
    // Le cas d'école de CLAUDE.md : un patronyme seul face à un nom complet.
    [InlineData("Hamilton", "Peter F. Hamilton")]
    [InlineData("Zola", "Émile Zola")]
    [InlineData("Cormen", "Thomas H. Cormen")]
    // Un prénom en plus, ou en moins.
    [InlineData("Émile Zola", "Émile Édouard Zola")]
    public void Les_rapprochements_ambigus_sont_seulement_proposes(string a, string b)
    {
        Assert.Equal(NiveauRapprochement.Suggere, RapprochementAuteurs.Comparer(a, b));
        Assert.Equal(NiveauRapprochement.Suggere, RapprochementAuteurs.Comparer(b, a));

        // Et surtout : jamais fusionnés d'office.
        Assert.False(RapprochementAuteurs.SontLeMemeAuteur(a, b));
    }

    [Theory]
    // Deux personnes qui partagent un patronyme : rien ne doit les rapprocher automatiquement.
    [InlineData("Peter Hamilton", "Paul Hamilton")]
    [InlineData("Peter F. Hamilton", "Peter G. Hamilton")]
    // Homonymes partiels sans mot entier commun.
    [InlineData("Émile Zola", "Émile Ajar")]
    [InlineData("Voltaire", "Molière")]
    // Une initiale seule ne concorde sur rien de vérifiable.
    [InlineData("P. H.", "Peter Hamilton")]
    [InlineData("P. Hamilton", "Peter Paul")]
    public void Les_auteurs_distincts_ne_sont_pas_rapproches(string a, string b)
    {
        Assert.Equal(NiveauRapprochement.Aucun, RapprochementAuteurs.Comparer(a, b));
        Assert.Equal(NiveauRapprochement.Aucun, RapprochementAuteurs.Comparer(b, a));
    }

    [Fact]
    public void Un_nom_vide_ne_se_rapproche_de_rien()
    {
        Assert.Equal(NiveauRapprochement.Aucun, RapprochementAuteurs.Comparer(null, "Émile Zola"));
        Assert.Equal(NiveauRapprochement.Aucun, RapprochementAuteurs.Comparer("  ", "Émile Zola"));
        Assert.Equal(NiveauRapprochement.Aucun, RapprochementAuteurs.Comparer(".,;", "Émile Zola"));
    }

    [Fact]
    public void La_cle_est_identique_pour_les_variantes_dordre_et_daccents()
    {
        var attendue = RapprochementAuteurs.Cle("Émile Zola");

        Assert.Equal(attendue, RapprochementAuteurs.Cle("Zola, Émile"));
        Assert.Equal(attendue, RapprochementAuteurs.Cle("emile zola"));
        Assert.Equal(attendue, RapprochementAuteurs.Cle("  ZOLA,  Emile  "));
        Assert.Equal("emile zola", attendue);
    }

    /// <summary>
    /// La clé ne sait pas rapprocher les initiales : c'est justement pour ça que
    /// <see cref="RapprochementAuteurs.Comparer"/> existe en plus de l'index unique.
    /// </summary>
    [Fact]
    public void La_cle_ne_couvre_pas_les_initiales()
    {
        Assert.NotEqual(
            RapprochementAuteurs.Cle("Peter F. Hamilton"),
            RapprochementAuteurs.Cle("P.F. Hamilton"));

        Assert.True(RapprochementAuteurs.SontLeMemeAuteur("Peter F. Hamilton", "P.F. Hamilton"));
    }

    [Theory]
    [InlineData("Émile ZOLA", "emile zola")]
    [InlineData("P.F. Hamilton", "p f hamilton")]
    [InlineData("  Zola,   Émile  ", "zola emile")]
    [InlineData("Saint-Exupéry", "saint exupery")]
    [InlineData("L'Écume", "l ecume")]
    [InlineData("", "")]
    [InlineData(null, "")]
    public void La_normalisation_met_a_plat_casse_accents_et_ponctuation(string? brut, string attendu)
        => Assert.Equal(attendu, NormalisationTexte.Normaliser(brut));

    /// <summary>
    /// La ponctuation devient une espace et ne disparaît pas : sans ça « P.F. » donnerait un seul
    /// mot et les initiales ne pourraient plus s'aligner.
    /// </summary>
    [Fact]
    public void La_ponctuation_separe_les_mots()
        => Assert.Equal(["p", "f", "hamilton"], NormalisationTexte.Mots("P.F. Hamilton"));
}
