"""Tests for Source Trust Level (Zero Trust Memory feature).

Source trust is application-specified (NOT LLM-judged) and governs:
- CONTRADICT resolution hierarchy (verified > input > derived)
- Search filtering (min_source_trust)
- Search ranking (source_trust > confidence > similarity)
"""
import pytest
from trustmem import TrustMem
from trustmem.constants import (
    DEFAULT_SOURCE_TRUST,
    SOURCE_TRUST_HIERARCHY,
    SOURCE_TRUST_LEVELS,
)


# ── Fixtures ─────────────────────────────────────────────────────


@pytest.fixture
def tm(handler):
    """TrustMem with mock handler."""
    return TrustMem._from_handler(handler)


# ── Basic CRUD ───────────────────────────────────────────────────


class TestSourceTrustBasic:
    """Basic source_trust storage and retrieval."""

    def test_default_source_trust_is_derived(self, tm):
        """Default source_trust should be 'derived'."""
        result = tm.add(
            [{"role": "user", "content": "test fact"}],
            user_id="test",
        )
        # Check that extracted memories have source_trust
        for item in result.get("extracted", []):
            if item.get("event") in ("ADD", "CONTRADICT"):
                assert item.get("source_trust") == "derived"

    def test_explicit_source_trust_input(self, tm):
        """Explicit source_trust='input' should be passed through."""
        result = tm.add(
            [{"role": "user", "content": "I live in Tokyo"}],
            user_id="test",
            source_trust="input",
        )
        for item in result.get("extracted", []):
            if item.get("event") in ("ADD", "CONTRADICT"):
                assert item.get("source_trust") == "input"

    def test_explicit_source_trust_verified(self, tm):
        """Explicit source_trust='verified' should be passed through."""
        result = tm.add(
            [{"role": "user", "content": "Contract plan is Business"}],
            user_id="test",
            source_trust="verified",
        )
        for item in result.get("extracted", []):
            if item.get("event") in ("ADD", "CONTRADICT"):
                assert item.get("source_trust") == "verified"

    def test_invalid_source_trust_raises(self, tm):
        """Invalid source_trust should raise ValidationError."""
        from trustmem.exceptions import ValidationError
        with pytest.raises(ValidationError, match="source_trust"):
            tm.add(
                [{"role": "user", "content": "test"}],
                source_trust="invalid_level",
                user_id="test",
            )

    def test_source_trust_in_memory_record(self, handler):
        """add_memory should store source_trust in the memory record."""
        result = handler.add_memory(
            user_id="test",
            content="Test memory",
            _source_trust="verified",
        )
        assert result["source_trust"] == "verified"

        # Verify stored in DB
        mem = handler._db.get_memory(result["memory_id"])
        assert mem["source_trust"] == "verified"

    def test_source_trust_default_in_memory(self, handler):
        """add_memory without source_trust should default to 'derived'."""
        result = handler.add_memory(
            user_id="test",
            content="Test memory no trust",
        )
        assert result["source_trust"] == "derived"

        mem = handler._db.get_memory(result["memory_id"])
        assert mem["source_trust"] == "derived"


# ── Search Filtering ─────────────────────────────────────────────


class TestSourceTrustSearch:
    """Search filtering by min_source_trust."""

    def test_search_includes_source_trust_in_results(self, handler):
        """Search results should include source_trust field."""
        handler.add_memory(
            user_id="test",
            content="fact one",
            _source_trust="verified",
        )
        result = handler.search_memory(user_id="test", query="fact")
        for r in result.get("results", []):
            assert "source_trust" in r

    def test_search_min_source_trust_verified(self, handler):
        """min_source_trust='verified' should only return verified memories."""
        handler.add_memory(user_id="test", content="derived fact", _source_trust="derived")
        handler.add_memory(user_id="test", content="input fact", _source_trust="input")
        handler.add_memory(user_id="test", content="verified fact", _source_trust="verified")

        result = handler.search_memory(
            user_id="test", query="fact", min_source_trust="verified",
        )
        for r in result.get("results", []):
            assert r["source_trust"] == "verified"

    def test_search_min_source_trust_input(self, handler):
        """min_source_trust='input' should return input + verified."""
        handler.add_memory(user_id="test", content="derived fact", _source_trust="derived")
        handler.add_memory(user_id="test", content="input fact", _source_trust="input")
        handler.add_memory(user_id="test", content="verified fact", _source_trust="verified")

        result = handler.search_memory(
            user_id="test", query="fact", min_source_trust="input",
        )
        trust_levels = {r["source_trust"] for r in result.get("results", [])}
        assert "derived" not in trust_levels

    def test_search_no_filter_returns_all(self, handler):
        """No min_source_trust should return all memories."""
        handler.add_memory(user_id="test", content="derived fact", _source_trust="derived")
        handler.add_memory(user_id="test", content="verified fact", _source_trust="verified")

        result = handler.search_memory(user_id="test", query="fact")
        assert result["count"] >= 2

    def test_sdk_search_min_source_trust(self, tm):
        """SDK search() should accept min_source_trust."""
        tm.add(
            [{"role": "user", "content": "some fact about cats"}],
            user_id="test",
        )
        # Should not raise
        result = tm.search("cats", user_id="test", min_source_trust="verified")
        assert "results" in result

    def test_sdk_get_all_min_source_trust(self, tm):
        """SDK get_all() should accept min_source_trust."""
        tm.add(
            [{"role": "user", "content": "another fact"}],
            user_id="test",
        )
        result = tm.get_all(user_id="test", min_source_trust="input")
        assert "results" in result


# ── CONTRADICT Hierarchy Override ────────────────────────────────


class TestSourceTrustContradict:
    """CONTRADICT resolution with source_trust hierarchy."""

    def test_lower_trust_cannot_override_higher(self, handler):
        """derived source cannot win against verified memory."""
        # Add a verified memory
        existing = handler.add_memory(
            user_id="test",
            content="Contract plan is Business",
            _source_trust="verified",
            _confidence="high",
        )
        existing_id = existing["memory_id"]

        # Simulate a CONTRADICT fact from derived source
        fact = {
            "content": "Contract plan is Free",
            "action": "CONTRADICT",
            "confidence": "high",
            "winner": "new",  # LLM says new wins
            "loser_confidence": "low",
            "conflict_with": existing_id,
        }

        record = handler._handle_contradict(
            fact, "Contract plan is Free", existing_id,
            add_tags=["test"], add_metadata={},
            source_trust="derived",  # lower than verified
            user_id="test",
        )

        # Source trust hierarchy should override LLM's winner=new
        assert record["winner"] == "existing"
        assert record["source_trust_override"] is True

        # Existing memory should NOT have its confidence downgraded
        existing_mem = handler._db.get_memory(existing_id)
        assert existing_mem["confidence"] == "high"  # unchanged

    def test_higher_trust_always_wins(self, handler):
        """verified source should always win against derived memory."""
        # Add a derived memory
        existing = handler.add_memory(
            user_id="test",
            content="Plan is Free",
            _source_trust="derived",
            _confidence="high",
        )
        existing_id = existing["memory_id"]

        # Simulate CONTRADICT from verified source
        fact = {
            "content": "Plan is Business",
            "action": "CONTRADICT",
            "confidence": "high",
            "winner": "existing",  # LLM says existing wins (wrong)
            "loser_confidence": "low",
            "conflict_with": existing_id,
        }

        record = handler._handle_contradict(
            fact, "Plan is Business", existing_id,
            add_tags=["test"], add_metadata={},
            source_trust="verified",  # higher than derived
            user_id="test",
        )

        # Source trust hierarchy should override LLM's winner=existing
        assert record["winner"] == "new"
        assert record["source_trust_override"] is True

    def test_same_trust_uses_llm_judgment(self, handler):
        """Same source_trust level should use LLM's winner judgment."""
        existing = handler.add_memory(
            user_id="test",
            content="Lives in Tokyo",
            _source_trust="input",
        )
        existing_id = existing["memory_id"]

        fact = {
            "content": "Lives in Osaka",
            "action": "CONTRADICT",
            "confidence": "high",
            "winner": "new",
            "loser_confidence": "low",
            "conflict_with": existing_id,
        }

        record = handler._handle_contradict(
            fact, "Lives in Osaka", existing_id,
            add_tags=["test"], add_metadata={},
            source_trust="input",  # same level
            user_id="test",
        )

        # No override — LLM judgment preserved
        assert record["winner"] == "new"
        assert record["source_trust_override"] is False

    def test_contradict_audit_trail_includes_override(self, handler):
        """Audit trail should record source_trust_override."""
        existing = handler.add_memory(
            user_id="test",
            content="Verified info",
            _source_trust="verified",
        )
        existing_id = existing["memory_id"]

        fact = {
            "content": "Contradicting info",
            "action": "CONTRADICT",
            "confidence": "medium",
            "winner": "new",
            "loser_confidence": "low",
            "conflict_with": existing_id,
        }

        handler._handle_contradict(
            fact, "Contradicting info", existing_id,
            add_tags=["test"], add_metadata={},
            source_trust="derived",
            user_id="test",
        )

        # Winner forced to "existing", so existing memory should NOT be downgraded
        existing_mem = handler._db.get_memory(existing_id)
        assert existing_mem["confidence"] != "low"


# ── Stats ────────────────────────────────────────────────────────


class TestSourceTrustStats:
    """Statistics include source_trust distribution."""

    def test_stats_include_source_trust_distribution(self, handler):
        """get_memory_stats should include source_trust_distribution."""
        handler.add_memory(user_id="test", content="fact1", _source_trust="verified")
        handler.add_memory(user_id="test", content="fact2", _source_trust="input")
        handler.add_memory(user_id="test", content="fact3", _source_trust="derived")

        stats = handler.get_memory_stats(user_id="test")
        assert "source_trust_distribution" in stats
        dist = stats["source_trust_distribution"]
        assert dist.get("verified", 0) >= 1
        assert dist.get("input", 0) >= 1
        assert dist.get("derived", 0) >= 1


# ── Constants ────────────────────────────────────────────────────


class TestSourceTrustConstants:
    """Verify constants are correctly defined."""

    def test_source_trust_levels(self):
        assert SOURCE_TRUST_LEVELS == ("verified", "input", "derived")

    def test_default_is_derived(self):
        assert DEFAULT_SOURCE_TRUST == "derived"

    def test_hierarchy_order(self):
        assert SOURCE_TRUST_HIERARCHY["verified"] > SOURCE_TRUST_HIERARCHY["input"]
        assert SOURCE_TRUST_HIERARCHY["input"] > SOURCE_TRUST_HIERARCHY["derived"]


# ── Migration ────────────────────────────────────────────────────


class TestSourceTrustMigration:
    """Schema migration adds source_trust column."""

    def test_migration_adds_column(self):
        """SQLiteStore migration should add source_trust column."""
        from trustmem.storage.sqlite_store import SQLiteStore
        store = SQLiteStore(":memory:")

        # Verify column exists
        cols = [
            row[1] for row in
            store._conn.execute("PRAGMA table_info(memories)").fetchall()
        ]
        assert "source_trust" in cols
        store.close()

    def test_migration_default_value(self):
        """Existing memories should get 'derived' as default."""
        from trustmem.storage.sqlite_store import SQLiteStore
        store = SQLiteStore(":memory:")

        # Insert a memory without source_trust
        store._conn.execute(
            "INSERT INTO memories (memory_id, user_id, content, created_at, updated_at) "
            "VALUES ('test-id', 'test', 'test content', '2024-01-01', '2024-01-01')"
        )
        store._conn.commit()

        row = store._conn.execute(
            "SELECT source_trust FROM memories WHERE memory_id = 'test-id'"
        ).fetchone()
        assert row[0] == "derived"
        store.close()
