"""Tests for Doc Anchor Reset (PROMPT 27, v3.3)."""
import sys
import os
import time

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from crews.agromatrix_crew import session_context as sc
from crews.agromatrix_crew.doc_facts import build_self_correction

FACTS_DOC_A = {
    "profit_uah": 5_972_016.0,
    "fertilizer_uah": 1_521_084.0,
    "area_ha": 497.0,
}


def _make_session(active_doc_id: str, doc_facts: dict, fact_claims: list | None = None) -> dict:
    sess = sc._default_session()
    sess["active_doc_id"] = active_doc_id
    sess["doc_facts"] = dict(doc_facts)
    sess["fact_claims"] = list(fact_claims or [])
    sess["updated_at"] = time.time()
    return sess


def _store_session(chat_id: str, sess: dict):
    sc._STORE[chat_id] = sess


# ── Основний сценарій: зміна doc_id → reset ──────────────────────────────────

def test_anchor_reset_clears_doc_facts():
    """При зміні doc_id — doc_facts скидаються."""
    chat_id = "anchor_test_1"
    sess = _make_session("docA", FACTS_DOC_A)
    _store_session(chat_id, sess)

    loaded = sc.load_session(chat_id)
    assert loaded["doc_facts"] == FACTS_DOC_A

    # Симулюємо логіку з run.py: новий doc_id != старий
    current_doc_id = "docB"
    prev_doc_id = loaded.get("active_doc_id")
    if prev_doc_id and prev_doc_id != current_doc_id:
        loaded["doc_facts"] = {}
        loaded["fact_claims"] = []

    assert loaded["doc_facts"] == {}
    assert loaded["fact_claims"] == []


def test_anchor_reset_clears_fact_claims():
    """При зміні doc_id — fact_claims також скидаються."""
    chat_id = "anchor_test_2"
    claims = [{"key": "profit_present", "value": True, "ts": time.time()}]
    sess = _make_session("docA", FACTS_DOC_A, fact_claims=claims)
    _store_session(chat_id, sess)

    loaded = sc.load_session(chat_id)
    assert len(loaded["fact_claims"]) == 1

    # Зміна doc_id
    current_doc_id = "docB"
    prev_doc_id = loaded.get("active_doc_id")
    if prev_doc_id and prev_doc_id != current_doc_id:
        loaded["doc_facts"] = {}
        loaded["fact_claims"] = []

    assert loaded["fact_claims"] == []


def test_anchor_reset_updates_active_doc_id():
    """Після reset active_doc_id має оновитися через update_session."""
    chat_id = "anchor_test_3"
    sess = _make_session("docA", FACTS_DOC_A)
    _store_session(chat_id, sess)

    # Виконуємо update_session з новим active_doc_id
    sc.update_session(chat_id, "текст", depth="deep", agents=[],
                      active_doc_id="docB", doc_facts={}, fact_claims=[])

    updated = sc.load_session(chat_id)
    assert updated["active_doc_id"] == "docB"
    assert updated["doc_facts"] == {}


# ── Fail-safe: якщо current_doc_id None → нічого не скидаємо ────────────────

def test_no_reset_when_current_doc_id_is_none():
    """Якщо current_doc_id не визначений — doc_facts НЕ скидаються."""
    chat_id = "anchor_test_failsafe"
    sess = _make_session("docA", FACTS_DOC_A)
    _store_session(chat_id, sess)

    loaded = sc.load_session(chat_id)
    current_doc_id = None  # невідомий

    # Логіка з run.py: якщо current_doc_id None — нічого не робимо
    if current_doc_id:
        prev = loaded.get("active_doc_id")
        if prev and prev != current_doc_id:
            loaded["doc_facts"] = {}
            loaded["fact_claims"] = []

    # doc_facts мають залишитись
    assert loaded["doc_facts"] == FACTS_DOC_A


def test_no_reset_when_same_doc_id():
    """Якщо doc_id той самий — doc_facts НЕ скидаються."""
    chat_id = "anchor_test_same"
    sess = _make_session("docA", FACTS_DOC_A)
    _store_session(chat_id, sess)

    loaded = sc.load_session(chat_id)
    current_doc_id = "docA"  # той самий

    prev = loaded.get("active_doc_id")
    if prev and prev != current_doc_id:
        loaded["doc_facts"] = {}
        loaded["fact_claims"] = []

    assert loaded["doc_facts"] == FACTS_DOC_A


def test_no_reset_when_no_previous_doc_id():
    """Якщо попереднього active_doc_id нема — reset не спрацьовує."""
    chat_id = "anchor_test_noprev"
    sess = sc._default_session()
    sess["doc_facts"] = FACTS_DOC_A
    sess["active_doc_id"] = None  # нема попереднього
    sess["updated_at"] = time.time()
    _store_session(chat_id, sess)

    loaded = sc.load_session(chat_id)
    current_doc_id = "docB"

    prev = loaded.get("active_doc_id")
    if prev and prev != current_doc_id:
        loaded["doc_facts"] = {}
        loaded["fact_claims"] = []

    # Нема попереднього — нічого не скинули
    assert loaded["doc_facts"] == FACTS_DOC_A


# ── Self-correction: тільки в межах одного doc_id ────────────────────────────

def test_self_correction_blocked_on_different_doc():
    """Self-correction НЕ спрацьовує при зміні doc_id."""
    sess = _make_session("docA", FACTS_DOC_A)
    sess["fact_claims"] = [{"key": "profit_present", "value": False, "ts": time.time()}]

    response = "У звіті є прибуток — 5 972 016 грн."
    # current_doc_id = docB (новий) → correction заблокована
    correction = build_self_correction(response, FACTS_DOC_A, sess, current_doc_id="docB")
    assert correction == "", f"Expected no correction, got: {correction!r}"


def test_self_correction_works_same_doc():
    """Self-correction спрацьовує в межах того самого doc_id."""
    sess = _make_session("docA", FACTS_DOC_A)
    sess["fact_claims"] = [{"key": "profit_present", "value": False, "ts": time.time()}]

    response = "У звіті є прибуток — 5 972 016 грн."
    correction = build_self_correction(response, FACTS_DOC_A, sess, current_doc_id="docA")
    assert correction, f"Expected correction prefix, got empty"
    assert "неточно" in correction.lower() or "написав" in correction.lower()


def test_self_correction_works_when_no_current_doc_id():
    """Self-correction не блокується якщо current_doc_id=None (backward-compat)."""
    sess = _make_session("docA", FACTS_DOC_A)
    sess["fact_claims"] = [{"key": "profit_present", "value": False, "ts": time.time()}]

    response = "У звіті є прибуток — 5 972 016 грн."
    # current_doc_id=None → anchor guard не спрацьовує → correction дозволена
    correction = build_self_correction(response, FACTS_DOC_A, sess, current_doc_id=None)
    assert correction, "Expected correction when current_doc_id is None"


# ── update_session: active_doc_id персистується ───────────────────────────────

def test_update_session_persists_active_doc_id():
    """update_session зберігає active_doc_id."""
    chat_id = "anchor_persist_test"
    sc.clear_session(chat_id)

    sc.update_session(chat_id, "запит", depth="deep", agents=[],
                      active_doc_id="doc_xyz123")

    sess = sc.load_session(chat_id)
    assert sess["active_doc_id"] == "doc_xyz123"


def test_update_session_preserves_doc_id_if_not_provided():
    """update_session зберігає існуючий active_doc_id якщо новий не передано."""
    chat_id = "anchor_preserve_test"
    sc.clear_session(chat_id)

    sc.update_session(chat_id, "перший", depth="deep", agents=[],
                      active_doc_id="docA")
    sc.update_session(chat_id, "другий", depth="light", agents=[])

    sess = sc.load_session(chat_id)
    # active_doc_id має залишитись "docA" (None не перезаписує)
    assert sess["active_doc_id"] == "docA"
