"""
Recollection rendering tests — hit path, zero-hit path, pending-conflict marker,
and prompt injection position.
"""
import pytest
from festinger import cache
from festinger.recollection import (
    query_edges, render_hit, render_zero_hit,
    build_recollection_block, inject_recollection,
)
from tests.helpers import reset_cache, add_soas, add_urd


class TestHitPath:

    def setup_method(self):
        reset_cache()
        self.michigan  = add_soas(101, "michigan",  saliency=1.5)
        self.usa       = add_soas(102, "usa",       saliency=0.8)
        self.geography = add_soas(5,   "geography", saliency=0.0)
        self.state     = add_soas(103, "state",     saliency=0.7)
        self.type_dim  = add_soas(1,   "type",      saliency=0.0)

        add_urd(concept_id=101, parent_id=102, dim_id=5, is_isa=False, confidence=0.9)
        add_urd(concept_id=101, parent_id=103, dim_id=1, is_isa=True,  confidence=0.9)

    def test_query_returns_both_edges(self):
        edges = query_edges(101, confidence_floor=0.5, recency_days=90)
        assert len(edges) == 2

    def test_render_hit_format(self):
        edges = query_edges(101, confidence_floor=0.5, recency_days=90)
        line = render_hit("michigan", edges, concept_id=101)
        assert line.startswith("michigan:")
        assert "[geography] usa" in line
        assert "[type] state" in line

    def test_pending_conflict_adds_question_mark(self):
        cache.pending_conflicts.add(101)
        edges = query_edges(101, confidence_floor=0.5, recency_days=90)
        line = render_hit("michigan", edges, concept_id=101)
        # All dim labels should have ? when concept has pending conflict
        assert "[geography?]" in line or "[type?]" in line

    def test_confidence_floor_filters_edges(self):
        # Add a low-confidence edge
        add_urd(concept_id=101, parent_id=5, dim_id=5, is_isa=False, confidence=0.2)
        edges = query_edges(101, confidence_floor=0.6, recency_days=90)
        # Should not include the 0.2 confidence edge
        low_conf = [e for e in edges if e.confidence < 0.6]
        assert low_conf == []

    def test_block_contains_recollection_tags(self):
        block = build_recollection_block([101], confidence_floor=0.5, recency_days=90)
        assert block is not None
        assert block.startswith("<recollection>")
        assert block.endswith("</recollection>")


class TestZeroHitPath:

    def setup_method(self):
        reset_cache()
        add_soas(201, "ramanujan", saliency=1.5)
        # No URD edges for ramanujan

    def test_zero_hit_render(self):
        line = render_zero_hit("ramanujan")
        assert "ramanujan" in line
        assert "no recollection" in line
        assert "gutask iknowthat" in line

    def test_zero_hit_in_block(self):
        block = build_recollection_block([201], confidence_floor=0.5, recency_days=90)
        assert block is not None
        assert "? ramanujan" in block
        assert "gutask iknowthat" in block

    def test_block_is_none_when_no_salient_concepts(self):
        block = build_recollection_block([], confidence_floor=0.5, recency_days=90)
        assert block is None


class TestPromptInjection:

    def setup_method(self):
        reset_cache()
        add_soas(101, "michigan", saliency=1.5)
        add_soas(102, "usa",      saliency=0.8)
        add_soas(5,   "geography", saliency=0.0)
        add_urd(concept_id=101, parent_id=102, dim_id=5, is_isa=False, confidence=0.9)

    def _block(self):
        return build_recollection_block([101], confidence_floor=0.5, recency_days=90)

    def test_injected_into_existing_system_message(self):
        messages = [
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user",   "content": "Tell me about michigan."},
        ]
        block = self._block()
        result = inject_recollection(messages, block)

        system = next(m for m in result if m["role"] == "system")
        assert system["content"].startswith("<recollection>")
        assert "You are a helpful assistant." in system["content"]

    def test_injected_at_position_0_when_no_system_message(self):
        messages = [{"role": "user", "content": "Tell me about michigan."}]
        block = self._block()
        result = inject_recollection(messages, block)

        assert result[0]["role"] == "system"
        assert "<recollection>" in result[0]["content"]
        assert result[1]["role"] == "user"

    def test_original_messages_not_mutated(self):
        original = [
            {"role": "system", "content": "You are helpful."},
            {"role": "user",   "content": "michigan?"},
        ]
        inject_recollection(original, self._block())
        # Original list and dicts must be unchanged
        assert original[0]["content"] == "You are helpful."

    def test_user_message_preserved_after_injection(self):
        messages = [
            {"role": "system", "content": "System prompt."},
            {"role": "user",   "content": "michigan?"},
        ]
        result = inject_recollection(messages, self._block())
        user_msgs = [m for m in result if m["role"] == "user"]
        assert user_msgs[0]["content"] == "michigan?"
