"""TDD — Service AI de cadrage des décisions (qualify/ai-chat).

Invariants testés :
  A1  Premier appel (messages=[]) → retourne toujours 2 questions, done=False
  A2  Les 2 questions couvrent réversibilité et urgence (ids stables)
  A3  Deuxième appel (messages=[q+réponse]) → done=True, résultat qualifié
  A4  Réponse "irréversible" → recommend_onchain conservé si is_structural
  A5  Réponse "urgente" → raison "urgence" présente dans le résultat
  A6  La qualification finale respecte les règles du moteur (R1/R2/R4/R5/R6)
  A7  Sans contexte, les questions restent les mêmes (stub ne dépend pas du LLM)
"""

from __future__ import annotations

import pytest

from app.services.qualify_ai_service import (
    AIFrameRequest,
    AIMessage,
    ai_frame,
)


DEFAULT_REQUEST = AIFrameRequest(
    context="Révision du règlement intérieur de l'association",
    within_mandate=False,
    affected_count=20,
    is_structural=False,
    messages=[],
)


# ---------------------------------------------------------------------------
# A1 — Premier appel → 2 questions, done=False
# ---------------------------------------------------------------------------


def test_a1_first_call_returns_questions():
    resp = ai_frame(DEFAULT_REQUEST)
    assert resp.done is False
    assert len(resp.questions) == 2


def test_a1_first_call_result_is_none():
    resp = ai_frame(DEFAULT_REQUEST)
    assert resp.result is None


# ---------------------------------------------------------------------------
# A2 — Questions couvrent réversibilité et urgence
# ---------------------------------------------------------------------------


def test_a2_questions_have_stable_ids():
    resp = ai_frame(DEFAULT_REQUEST)
    ids = {q.id for q in resp.questions}
    assert "reversibility" in ids
    assert "urgency" in ids


def test_a2_questions_have_options():
    resp = ai_frame(DEFAULT_REQUEST)
    for q in resp.questions:
        assert len(q.options) >= 2, f"Question '{q.id}' doit avoir au moins 2 options"


# ---------------------------------------------------------------------------
# A3 — Deuxième appel (avec réponses) → done=True + résultat
# ---------------------------------------------------------------------------


def _make_second_request(reversibility_ans: str, urgency_ans: str, **kwargs) -> AIFrameRequest:
    questions = ai_frame(DEFAULT_REQUEST).questions
    messages = []
    for q in questions:
        messages.append(AIMessage(role="assistant", content=q.text))
    # One user message bundling all answers
    messages.append(AIMessage(
        role="user",
        content=f"reversibility:{reversibility_ans}|urgency:{urgency_ans}",
    ))
    return AIFrameRequest(
        **{**vars(DEFAULT_REQUEST), "messages": messages, **kwargs}
    )


def test_a3_second_call_is_done():
    req = _make_second_request("Difficilement", "Pas d'urgence")
    resp = ai_frame(req)
    assert resp.done is True


def test_a3_second_call_has_result():
    req = _make_second_request("Difficilement", "Pas d'urgence")
    resp = ai_frame(req)
    assert resp.result is not None
    assert resp.result.decision_type in ("individual", "collective")


# ---------------------------------------------------------------------------
# A4 — Irréversible + structurant → recommend_onchain
# ---------------------------------------------------------------------------


def test_a4_irreversible_structural_recommends_onchain():
    req = _make_second_request(
        "Non, c'est irréversible",
        "Pas d'urgence",
        is_structural=True,
    )
    resp = ai_frame(req)
    assert resp.result is not None
    assert resp.result.recommend_onchain is True


# ---------------------------------------------------------------------------
# A5 — Urgence → raison présente
# ---------------------------------------------------------------------------


def test_a5_urgent_adds_urgency_reason():
    req = _make_second_request("Oui, facilement", "Urgente (< 1 semaine)")
    resp = ai_frame(req)
    assert resp.result is not None
    reasons_text = " ".join(resp.result.reasons).lower()
    assert "urgence" in reasons_text or "urgent" in reasons_text


# ---------------------------------------------------------------------------
# A6 — Résultat respecte les règles du moteur
# ---------------------------------------------------------------------------


def test_a6_within_mandate_gives_individual():
    req = AIFrameRequest(
        within_mandate=True,
        affected_count=None,
        messages=[
            AIMessage(role="assistant", content="q"),
            AIMessage(role="user", content="reversibility:Facilement|urgency:Pas d'urgence"),
        ],
    )
    resp = ai_frame(req)
    assert resp.done is True
    assert resp.result is not None
    assert resp.result.decision_type == "individual"
    assert resp.result.process == "consultation_avis"


def test_a6_large_group_gives_collective():
    req = _make_second_request("Difficilement", "Pas d'urgence", affected_count=100)
    resp = ai_frame(req)
    assert resp.result is not None
    assert resp.result.decision_type == "collective"


# ---------------------------------------------------------------------------
# A7 — Sans contexte, mêmes questions (stub ne dépend pas du LLM)
# ---------------------------------------------------------------------------


def test_a7_no_context_same_question_ids():
    req_with = DEFAULT_REQUEST
    req_without = AIFrameRequest(
        context=None,
        within_mandate=False,
        affected_count=20,
        messages=[],
    )
    ids_with = {q.id for q in ai_frame(req_with).questions}
    ids_without = {q.id for q in ai_frame(req_without).questions}
    assert ids_with == ids_without
