"""Integration tests for PersistentHandler with VectorStore + AIClient.

Tests the handler with SQLiteVectorStore and a mock AIClient
to verify end-to-end memory operations work with the plugin architecture.
All data is persisted in SQLite (in-memory mode for tests).
"""

import pytest

from conftest import MockAIClient
from trustmem.handler.persistent import PersistentHandler


# ============================================================
# Fixtures
# ============================================================


@pytest.fixture
def handler():
    ai = MockAIClient()
    h = PersistentHandler(database_url=":memory:", ai_client=ai)
    h.reset_stores()
    return h


# ============================================================
# Core CRUD with VectorStore integration
# ============================================================


class TestAddWithVectorStore:
    def test_add_stores_in_vectorstore(self, handler):
        result = handler.add_memory("Python programming", user_id="test")
        assert result["memory_id"]
        # Verify vectorstore has the entry
        assert handler._vs.count() == 1

    def test_add_multiple(self, handler):
        handler.add_memory("First memory", user_id="test")
        handler.add_memory("Second memory", user_id="test")
        assert handler._vs.count() == 2

    def test_add_returns_expected_keys(self, handler):
        result = handler.add_memory("Some content", user_id="test")
        assert "memory_id" in result
        assert "content_hash" in result
        assert "confidence" in result
        assert "embedding_status" in result

    def test_add_default_confidence(self, handler):
        result = handler.add_memory("Default confidence content", user_id="test")
        assert result["confidence"] in ("high", "medium", "low")

    def test_add_with_confidence_high(self, handler):
        result = handler.add_memory("High confidence fact", _confidence="high", user_id="test")
        assert result["confidence"] == "high"

    def test_add_with_confidence_medium(self, handler):
        result = handler.add_memory("Medium confidence fact", _confidence="medium", user_id="test")
        assert result["confidence"] == "medium"

    def test_add_with_confidence_low(self, handler):
        result = handler.add_memory("Low confidence fact", _confidence="low", user_id="test")
        assert result["confidence"] == "low"


class TestSearchWithVectorStore:
    def test_search_uses_vectorstore(self, handler):
        handler.add_memory("Python is great for data science", user_id="test")
        handler.add_memory("JavaScript is used for web development", user_id="test")
        handler.add_memory("Python machine learning frameworks", user_id="test")

        result = handler.search_memory("Python data", limit=5, user_id="test")
        assert result["count"] >= 1

    def test_search_returns_confidence(self, handler):
        handler.add_memory("First fact", _confidence="high", user_id="test")
        result = handler.search_memory("fact", user_id="test")
        assert result["count"] >= 1
        for r in result["results"]:
            assert "confidence" in r
            assert r["confidence"] in ("high", "medium", "low")

    def test_search_returns_expected_fields(self, handler):
        handler.add_memory("Test memory content", user_id="test")
        result = handler.search_memory("test memory", user_id="test")
        assert result["count"] >= 1
        mem = result["results"][0]
        assert "memory_id" in mem
        assert "content" in mem
        assert "similarity" in mem
        assert "confidence" in mem
        assert "tags" in mem
        assert "created_at" in mem
        assert "last_evaluated_at" in mem
        assert "freshness" in mem

    def test_search_no_zone_filter(self, handler):
        """search_memory has no min_zone param — all memories are returned."""
        handler.add_memory("First fact", user_id="test")
        handler.add_memory("Second fact", user_id="test")

        result = handler.search_memory("fact", user_id="test")
        assert len(result["results"]) >= 1

    def test_search_limit(self, handler):
        for i in range(5):
            handler.add_memory(f"Memory number {i}", user_id="test")
        result = handler.search_memory("memory", limit=3, user_id="test")
        assert result["count"] <= 3


class TestDeleteWithVectorStore:
    def test_delete_removes_from_vectorstore(self, handler):
        result = handler.add_memory("To be deleted", user_id="test")
        mid = result["memory_id"]
        assert handler._vs.count() == 1
        handler.delete_memory(mid)
        assert handler._vs.count() == 0


# ============================================================
# Content Hash / Integrity
# ============================================================


class TestIntegrity:
    def test_content_hash_generated(self, handler):
        result = handler.add_memory("Hash me", user_id="test")
        assert result["content_hash"].startswith("mem_")
        assert len(result["content_hash"]) == 44  # "mem_" + 40 hex chars

    def test_verify_intact(self, handler):
        result = handler.add_memory("Verify me", user_id="test")
        v = handler.verify_memory(result["memory_id"])
        assert v["valid"] is True

    def test_verify_all(self, handler):
        handler.add_memory("First", user_id="test")
        handler.add_memory("Second", user_id="test")
        result = handler.verify_all_memories()
        assert result["total"] == 2
        assert result["valid"] == 2
        assert result["invalid"] == 0


# ============================================================
# Provenance
# ============================================================


class TestProvenance:
    def test_provenance_recorded_via_contradict(self, handler):
        """Provenance (contradicts edge) is recorded by _handle_contradict."""
        parent = handler.add_memory("Parent memory", user_id="test")
        parent_id = parent["memory_id"]

        # Directly invoke _handle_contradict to produce a contradicts provenance edge
        handler._handle_contradict(
            fact={"confidence": "medium"},
            content="Contradicting child memory",
            conflict_with=parent_id,
            user_id="a",
            add_tags=["test"],
            add_metadata={},
        )
        prov = handler._db.get_provenance_by_parent(parent_id)
        assert len(prov) == 1
        assert prov[0]["relationship"] == "contradicts"


# ============================================================
# Audit Trail
# ============================================================


class TestAuditTrail:
    def test_audit_trail_recorded_on_add(self, handler):
        result = handler.add_memory("Audited memory", user_id="test")
        trail = handler.get_audit_trail(result["memory_id"])
        assert len(trail) >= 1
        assert trail[0]["event_type"] == "memory_created"

    def test_record_audit_trail_manual(self, handler):
        result = handler.add_memory("Manual audit memory", user_id="test")
        mid = result["memory_id"]
        entry = handler.record_audit_trail(
            memory_id=mid,
            event_type="test_event",
            triggered_by="test",
            detail={"note": "manual test"},
            old_confidence="medium",
            new_confidence="high",
        )
        assert entry["memory_id"] == mid
        assert entry["event_type"] == "test_event"
        assert entry["old_confidence"] == "medium"
        assert entry["new_confidence"] == "high"

    def test_get_audit_trail_limit(self, handler):
        result = handler.add_memory("Multi-audit memory", user_id="test")
        mid = result["memory_id"]
        for i in range(5):
            handler.record_audit_trail(mid, f"event_{i}")
        trail = handler.get_audit_trail(mid, limit=3)
        assert len(trail) <= 3


# ============================================================
# Factory
# ============================================================


class TestFactory:
    def test_create_persistent_with_defaults(self, monkeypatch):
        from trustmem.config import TrustMemConfig
        from trustmem.handler.factory import create_handler

        monkeypatch.setenv("OPENAI_API_KEY", "test-key")
        config = TrustMemConfig(
            handler_mode="persistent",
            openai_api_key="test-key",
            database_url=":memory:",
        )
        h = create_handler(config)
        assert isinstance(h, PersistentHandler)

    def test_create_snowflake_raises(self):
        from trustmem.config import TrustMemConfig
        from trustmem.handler.factory import create_handler

        config = TrustMemConfig(handler_mode="snowflake")
        with pytest.raises(ValueError, match="Unknown handler_mode"):
            create_handler(config)
