"""Tests purs de `_strip_reasoning` (retrait de la chaine de pensee).

Sans charger de modele : on verifie que la pensee est retiree et que
`_extract_json` recupere bien la reponse FINALE (et non un fragment JSON
parasite present dans la pensee).
"""
from __future__ import annotations

from inkflow.analysis.gemma import (
    _extract_json,
    _has_complete_json,
    _strip_reasoning,
)


def test_has_complete_json_arret_anticipe():
    # JSON complet -> True (on peut stopper la generation)
    assert _has_complete_json('voici: {"speaker": "Marie"}')
    assert _has_complete_json('[{"a": 1}]')
    # JSON tronque (reponse pas encore finie) -> False (on continue)
    assert not _has_complete_json('{"speaker": "Mar')
    assert not _has_complete_json('texte sans json')
    # cas streaming reel : pensee close + fence json en cours mais objet complet
    buf = _strip_reasoning('<think>...</think>```json\n{"speaker": "Marie"}')
    assert _has_complete_json(buf)


def test_format_a_canaux_gemma4():
    raw = (
        "<|channel>thought\n"
        "Thinking Process: la capitale est Paris. Exemple: {\"capitale\": \"...\"}\n"
        "<channel|>```json\n{\"capitale\": \"Paris\"}\n```"
    )
    cleaned = _strip_reasoning(raw)
    # la pensee (et son JSON d'exemple parasite) a disparu
    assert "Thinking Process" not in cleaned
    assert '"..."' not in cleaned
    # le JSON extrait est bien la reponse finale
    assert _extract_json(cleaned) == {"capitale": "Paris"}


def test_balises_think_deepseek():
    raw = "<think>je reflechis, peut-etre [1,2]</think>\n[{\"speaker\": \"Holden\"}]"
    cleaned = _strip_reasoning(raw)
    assert "reflechis" not in cleaned
    assert _extract_json(cleaned) == [{"speaker": "Holden"}]


def test_sans_raisonnement_inchange():
    raw = '{"speaker": "Kajri"}'
    assert _strip_reasoning(raw) == raw
    assert _extract_json(_strip_reasoning(raw)) == {"speaker": "Kajri"}


def test_pensee_tronquee_sans_fermeture():
    # pensee non fermee (budget de tokens epuise) : le prefixe de canal saute,
    # on ne renvoie pas le marqueur d'ouverture.
    raw = "<|channel>thought\nje commence a reflechir mais c'est coupe"
    cleaned = _strip_reasoning(raw)
    assert not cleaned.startswith("<|channel")
    assert "<channel" not in cleaned


def test_dernier_marqueur_gagne():
    # plusieurs blocs : seule la derniere reponse finale compte
    raw = "<think>a</think>milieu<think>b</think>FINAL"
    assert _strip_reasoning(raw) == "FINAL"
