"""Vérifie le round-trip entraînement -> prédiction du `textcat` (la partie
"comprendre le sens, pas juste les mots clés" du pipeline — voir le
commentaire de `tech-step-matcher.ts` côté apps/api pour la motivation
d'origine)."""

from intent_service.locale_pipeline import LocalePipeline, TrainEntry

_ENTRIES = [
    TrainEntry(
        uid="melt",
        synonyms=["faire fondre"],
        utterances=[
            "faire fondre le beurre à feu doux",
            "laisser fondre le beurre dans la poêle",
            "jusqu'à ce que le beurre ait disparu",
            "jusqu'à ce que le beurre ait complètement disparu dans la poêle",
        ],
    ),
    TrainEntry(
        uid="boil",
        synonyms=["bouillir"],
        utterances=[
            "porter l'eau à ébullition",
            "faire bouillir l'eau salée",
            "laisser bouillir quelques minutes",
            "porter à ébullition puis baisser le feu",
        ],
    ),
]


def test_train_returns_label_example_and_synonym_counts():
    pipeline = LocalePipeline("fr")
    label_count, example_count, synonym_count = pipeline.train(_ENTRIES)
    assert label_count == 2
    # `example_count` couvre les utterances *et* les synonyms (voir
    # LocalePipeline.train — les synonymes sont aussi des exemples
    # d'entraînement pour le textcat, pas seulement pour le PhraseMatcher).
    expected_examples = sum(len(entry.utterances) + len(entry.synonyms) for entry in _ENTRIES)
    assert example_count == expected_examples
    assert synonym_count == sum(len(entry.synonyms) for entry in _ENTRIES)
    assert pipeline.is_trained is True


def test_classifies_a_paraphrase_never_using_the_techniques_own_verb():
    # Le cas motivant tout le pipeline (voir tech-step-matcher.ts) : aucune
    # forme de "fondre" dans cette phrase, mais elle ne peut raisonnablement
    # signifier que `melt` une fois le textcat entraîné sur les paraphrases
    # ci-dessus.
    pipeline = LocalePipeline("fr")
    pipeline.train(_ENTRIES)

    result = pipeline.process("jusqu'à ce que le beurre ait disparu dans la poêle")
    assert result.intent == "melt"
    assert result.score > 0.5


def test_empty_entries_leaves_the_pipeline_untrained():
    pipeline = LocalePipeline("fr")
    pipeline.train([])
    assert pipeline.is_trained is False
    result = pipeline.process("faire fondre le beurre")
    assert result.intent is None
    assert result.entities == []


def test_retraining_replaces_the_previous_textcat_rather_than_accumulating():
    # `textcat` (exclusive_classes) exige >= 2 labels (voir la note dans
    # LocalePipeline.train) — le second entraînement garde donc 2 entrées,
    # mais remplace "boil" par une technique différente ("chop"), pour
    # vérifier que "boil" ne peut plus jamais ressortir après coup (pas de
    # fusion incrémentale — voir la doc de `LocalePipeline.train`).
    pipeline = LocalePipeline("fr")
    pipeline.train(_ENTRIES)

    chop_entry = TrainEntry(uid="chop", synonyms=["couper"], utterances=["couper les légumes en dés"])
    pipeline.train([_ENTRIES[0], chop_entry])

    result = pipeline.process("porter l'eau à ébullition")
    assert result.intent != "boil"
