"""Logique de l'assistant testée sans base : le seuil « sourcé ou silencieux »
et la sélection des suggestions — la partie SQL est couverte par la recette
réelle (convention R5.1 : pytest purs en CI)."""

from siop_ai.assistant import (
    CHAMPS_BILAN,
    SEUIL_CONFIANCE_FORTE,
    SEUIL_PERTINENCE,
    SEUIL_SUGGESTION,
    _cosinus,
)
from siop_ai.embeddings import EmbeddeurDeterministe


def test_les_seuils_sont_ordonnes():
    # Pertinence et suggestion vivent dans des pipelines distincts (question →
    # passages vs description → libellés) : pas d'ordre imposé entre eux.
    # L'invariant : une suggestion tout juste retenue n'est jamais « forte ».
    assert 0 < SEUIL_PERTINENCE < 1
    assert 0 < SEUIL_SUGGESTION < SEUIL_CONFIANCE_FORTE < 1


def test_champs_bilan_couvrent_les_six_champs_du_contrat():
    assert set(CHAMPS_BILAN) == {
        "DOOR_STATE",
        "CABIN_POSITION",
        "ANOMALY",
        "EXTERNAL_CAUSE",
        "ACTION_TAKEN",
        "COMPONENT_CONCERNED",
    }


def test_similarite_discrimine_le_bon_code():
    """Le cœur de la suggestion : une description de panne de porte doit être
    plus proche du code « portes » que d'un code sans rapport."""
    embeddeur = EmbeddeurDeterministe()
    description, porte, treuil = embeddeur.encoder(
        [
            "la porte cabine rebondit, cellule encrassée, nettoyage barrière porte",
            "anomalie constatée : cellule ou barrière de porte encrassée",
            "élément concerné : treuil et moteur de traction",
        ]
    )
    assert _cosinus(description, porte) > _cosinus(description, treuil)


def test_cosinus_de_vecteurs_normes():
    embeddeur = EmbeddeurDeterministe()
    [v] = embeddeur.encoder(["contrôle mensuel des portes palières"])
    assert abs(_cosinus(v, v) - 1.0) < 1e-6
