"""Tests for SQLite persistence in PersistentHandler.

Verifies that data survives handler re-instantiation,
SQLiteStore CRUD operations work correctly, and the
PersistentHandler correctly delegates to SQLiteStore.
"""
import os
import tempfile

import pytest

from conftest import MockAIClient
from trustmem.storage.sqlite_store import SQLiteStore
from trustmem.handler.persistent import PersistentHandler


# ============================================================
# SQLiteStore unit tests
# ============================================================


class TestSQLiteStoreMemories:
    def test_put_and_get(self):
        db = SQLiteStore(":memory:")
        db.put_memory({
            "memory_id": "m1",
            "user_id": "a1",
            "content": "Hello world",
            "tags": ["greeting"],
            "metadata": {"source": "test"},
            "created_at": "2025-01-01T00:00:00",
        })
        mem = db.get_memory("m1")
        assert mem is not None
        assert mem["content"] == "Hello world"
        assert mem["tags"] == ["greeting"]
        assert mem["metadata"] == {"source": "test"}
        db.close()

    def test_get_nonexistent(self):
        db = SQLiteStore(":memory:")
        assert db.get_memory("nonexistent") is None
        db.close()

    def test_delete(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x"})
        assert db.delete_memory("m1") is True
        assert db.get_memory("m1") is None
        assert db.delete_memory("m1") is False
        db.close()

    def test_update(self):
        db = SQLiteStore(":memory:")
        db.put_memory({
            "memory_id": "m1", "user_id": "a1", "content": "old",
            "confidence": "high",
        })
        db.update_memory("m1", {"confidence": "low"})
        mem = db.get_memory("m1")
        assert mem["confidence"] == "low"
        db.close()

    def test_list_by_user(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x", "created_at": "2025-01-01"})
        db.put_memory({"memory_id": "m2", "user_id": "a1", "content": "y", "created_at": "2025-01-02"})
        db.put_memory({"memory_id": "m3", "user_id": "a2", "content": "z", "created_at": "2025-01-03"})
        mems = db.list_memories_multi( user_id="a1")
        assert len(mems) == 2
        db.close()

    def test_count(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x"})
        db.put_memory({"memory_id": "m2", "user_id": "a1", "content": "y"})
        db.put_memory({"memory_id": "m3", "user_id": "a2", "content": "z"})
        assert db.count_memories() == 3
        db.close()

    def test_get_by_ids(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x"})
        db.put_memory({"memory_id": "m2", "user_id": "a1", "content": "y"})
        db.put_memory({"memory_id": "m3", "user_id": "a1", "content": "z"})
        result = db.get_memories_by_ids(["m1", "m3"])
        assert len(result) == 2
        assert "m1" in result
        assert "m3" in result
        db.close()


class TestSQLiteStoreProvenance:
    def test_put_and_query(self):
        db = SQLiteStore(":memory:")
        # Create prerequisite memories for FK constraints
        db.put_memory({"memory_id": "c1", "user_id": "a1", "content": "child"})
        db.put_memory({"memory_id": "p1", "user_id": "a1", "content": "parent"})
        db.put_provenance({
            "provenance_id": "prov1",
            "child_memory_id": "c1",
            "parent_memory_id": "p1",
            "user_id": "a1",
            "relationship": "derived_from",
        })
        result = db.get_provenance_by_child("c1")
        assert len(result) == 1
        assert result[0]["parent_memory_id"] == "p1"
        db.close()


class TestSQLiteStoreAuditTrail:
    def test_put_and_query(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x"})
        db.put_audit_trail({
            "audit_id": "a1",
            "memory_id": "m1",
            "event_type": "memory_created",
            "new_confidence": "high",
            "details": {"source_trust": "derived"},
        })
        trail = db.get_audit_trail("m1")
        assert len(trail) == 1
        assert trail[0]["details"]["source_trust"] == "derived"
        db.close()


class TestSQLiteStoreClearAll:
    def test_clear(self):
        db = SQLiteStore(":memory:")
        db.put_memory({"memory_id": "m1", "user_id": "a1", "content": "x"})
        db.clear_all()
        assert db.get_memory("m1") is None
        db.close()


# ============================================================
# File-based persistence tests
# ============================================================


class TestFilePersistence:
    """Verify data survives SQLiteStore re-instantiation with file DB."""

    def test_data_survives_reopen(self, tmp_path):
        db_path = str(tmp_path / "test.db")

        # Write data
        db1 = SQLiteStore(db_path)
        db1.put_memory({"memory_id": "m1", "user_id": "a1", "content": "persisted"})
        db1.close()

        # Reopen and verify
        db2 = SQLiteStore(db_path)
        mem = db2.get_memory("m1")
        assert mem is not None
        assert mem["content"] == "persisted"
        db2.close()


# ============================================================
# PersistentHandler persistence tests
# ============================================================


class TestHandlerPersistence:
    """Verify PersistentHandler data survives re-instantiation."""

    def test_memories_survive_reinit(self, tmp_path):
        db_path = str(tmp_path / "handler.db")

        # Create handler, add memory
        h1 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h1.add_memory("Important fact", user_id="agent-1")
        mid = result["memory_id"]

        # Create new handler with same DB
        h2 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        mem = h2._db.get_memory(mid)
        assert mem is not None
        assert mem["content"] == "Important fact"

    def test_add_memory_returns_expected_fields(self, tmp_path):
        db_path = str(tmp_path / "handler.db")
        h = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h.add_memory("Some fact", _confidence="high", user_id="test")
        assert "memory_id" in result
        assert "content_hash" in result
        assert result["confidence"] == "high"
        assert "embedding_status" in result
        # Legacy fields must not be present
        assert "trust_score" not in result
        assert "zone" not in result

    def test_audit_trail_survives_reinit(self, tmp_path):
        db_path = str(tmp_path / "handler.db")

        h1 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h1.add_memory("Audited memory", user_id="test")
        mid = result["memory_id"]

        h2 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        trail = h2.get_audit_trail(mid)
        assert len(trail) >= 1
        assert trail[0]["event_type"] == "memory_created"

    def test_audit_trail_uses_confidence_fields(self, tmp_path):
        db_path = str(tmp_path / "handler.db")
        h = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h.add_memory("Audited memory", _confidence="medium", user_id="test")
        mid = result["memory_id"]
        trail = h.get_audit_trail(mid)
        assert len(trail) >= 1
        entry = trail[0]
        # ZTM v2: audit trail uses old_confidence / new_confidence
        assert "new_confidence" in entry
        assert "old_confidence" in entry
        # Legacy fields must not be present
        assert "old_zone" not in entry
        assert "new_zone" not in entry
        assert "old_trust" not in entry
        assert "new_trust" not in entry

    def test_record_audit_trail_signature(self, tmp_path):
        db_path = str(tmp_path / "handler.db")
        h = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h.add_memory("Traceable memory", user_id="test")
        mid = result["memory_id"]
        entry = h.record_audit_trail(
            mid,
            "test_event",
            triggered_by="test",
            detail={"key": "value"},
            old_confidence="medium",
            new_confidence="high",
        )
        assert entry["event_type"] == "test_event"
        assert entry["old_confidence"] == "medium"
        assert entry["new_confidence"] == "high"

    def test_search_after_reinit(self, tmp_path):
        db_path = str(tmp_path / "handler.db")
        ai = MockAIClient()

        h1 = PersistentHandler(database_url=db_path, ai_client=ai)
        h1.add_memory("Python programming language", user_id="test")

        # New handler — vectors are persisted in SQLite, no sharing needed
        h2 = PersistentHandler(database_url=db_path, ai_client=ai)
        result = h2.search_memory("Python", user_id="test")
        assert result["count"] >= 1

    def test_search_result_has_confidence_not_trust_score(self, tmp_path):
        db_path = str(tmp_path / "handler.db")
        ai = MockAIClient()
        h = PersistentHandler(database_url=db_path, ai_client=ai)
        h.add_memory("Python programming language", _confidence="high", user_id="test")
        result = h.search_memory("Python", user_id="test")
        assert result["count"] >= 1
        mem = result["results"][0]
        assert "confidence" in mem
        assert mem["confidence"] in ("high", "medium", "low")
        assert "trust_score" not in mem
        assert "zone" not in mem
        assert "is_contaminated" not in mem
        assert "corroboration_count" not in mem

    def test_verify_after_reinit(self, tmp_path):
        db_path = str(tmp_path / "handler.db")

        h1 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        result = h1.add_memory("Verifiable content", user_id="test")
        mid = result["memory_id"]

        h2 = PersistentHandler(database_url=db_path, ai_client=MockAIClient())
        v = h2.verify_memory(mid)
        assert v["valid"] is True
