"""Comprehensive tests for procedural store and semantic store operations."""

import os
import tempfile
from mnemosynth.core.types import MemoryNode, MemoryType, MemoryStatus
from mnemosynth.core.config import MnemosynthConfig
from mnemosynth.utils.db import DatabaseManager
from mnemosynth.stores.procedural import ProceduralStore
from mnemosynth.stores.semantic import SemanticStore


class TestProceduralStore:
    def setup_method(self):
        self.tmp = tempfile.mkdtemp()
        self.config = MnemosynthConfig(data_dir=self.tmp)
        self.config.ensure_dirs()
        self.store = ProceduralStore(self.config)

    # ── CRUD ──────────────────────────────────────────────────

    def test_add_and_get(self):
        node = MemoryNode.create(
            content="Tool: git commit -m 'message'",
            memory_type=MemoryType.PROCEDURAL,
        )
        self.store.add(node)
        result = self.store.get(node.id)
        assert result is not None
        assert result.content == "Tool: git commit -m 'message'"

    def test_update(self):
        node = MemoryNode.create(content="Old tool", memory_type=MemoryType.PROCEDURAL)
        self.store.add(node)
        node.content = "Updated tool definition"
        self.store.update(node)
        result = self.store.get(node.id)
        assert result.content == "Updated tool definition"

    def test_delete(self):
        node = MemoryNode.create(content="To delete", memory_type=MemoryType.PROCEDURAL)
        self.store.add(node)
        assert self.store.delete(node.id) is True
        assert self.store.get(node.id) is None

    def test_delete_nonexistent(self):
        assert self.store.delete("nonexistent-id") is False

    def test_count(self):
        assert self.store.count() == 0
        self.store.add(MemoryNode.create(content="Tool 1", memory_type=MemoryType.PROCEDURAL))
        self.store.add(MemoryNode.create(content="Tool 2", memory_type=MemoryType.PROCEDURAL))
        assert self.store.count() == 2

    # ── Search ────────────────────────────────────────────────

    def test_search_by_keyword(self):
        self.store.add(MemoryNode.create(content="Docker deploy: docker compose up", memory_type=MemoryType.PROCEDURAL))
        self.store.add(MemoryNode.create(content="Git workflow: git push origin main", memory_type=MemoryType.PROCEDURAL))
        results = self.store.search("docker", limit=5)
        assert len(results) >= 1
        assert "Docker" in results[0].content or "docker" in results[0].content

    def test_search_no_results(self):
        results = self.store.search("nonexistent-tool")
        assert len(results) == 0

    def test_search_limit(self):
        for i in range(10):
            self.store.add(MemoryNode.create(
                content=f"Python tool number {i}",
                memory_type=MemoryType.PROCEDURAL,
            ))
        results = self.store.search("Python", limit=3)
        assert len(results) <= 3

    # ── Persistence ───────────────────────────────────────────

    def test_persistence_across_instances(self):
        self.store.add(MemoryNode.create(content="Persistent tool", memory_type=MemoryType.PROCEDURAL))
        # Create new store instance from same dir
        store2 = ProceduralStore(self.config)
        assert store2.count() == 1

    # ── List all ──────────────────────────────────────────────

    def test_list_all_active(self):
        active = MemoryNode.create(content="Active tool", memory_type=MemoryType.PROCEDURAL)
        deprecated = MemoryNode.create(content="Old tool", memory_type=MemoryType.PROCEDURAL)
        deprecated.status = MemoryStatus.DEPRECATED
        
        self.store.add(active)
        self.store.add(deprecated)
        
        all_active = self.store.list_all()
        assert len(all_active) == 1


class TestSemanticStore:
    def setup_method(self):
        self.tmp = tempfile.mkdtemp()
        self.config = MnemosynthConfig(data_dir=self.tmp)
        self.config.ensure_dirs()
        self.db = DatabaseManager(os.path.join(self.tmp, "memory.db"))
        self.store = SemanticStore(self.config, self.db)

    # ── CRUD ──────────────────────────────────────────────────

    def test_add_and_get(self):
        node = MemoryNode.create(content="Python is a programming language", memory_type=MemoryType.SEMANTIC)
        self.store.add(node)
        result = self.store.get(node.id)
        assert result is not None
        assert "Python" in result.content

    def test_delete(self):
        node = MemoryNode.create(content="To remove", memory_type=MemoryType.SEMANTIC)
        self.store.add(node)
        assert self.store.delete(node.id) is True
        assert self.store.get(node.id) is None

    def test_count(self):
        assert self.store.count() == 0
        self.store.add(MemoryNode.create(content="Fact 1", memory_type=MemoryType.SEMANTIC))
        self.store.add(MemoryNode.create(content="Fact 2", memory_type=MemoryType.SEMANTIC))
        assert self.store.count() == 2

    # ── Search ────────────────────────────────────────────────

    def test_search_by_keyword(self):
        self.store.add(MemoryNode.create(content="User prefers Python for backend", memory_type=MemoryType.SEMANTIC))
        self.store.add(MemoryNode.create(content="Project uses React for frontend", memory_type=MemoryType.SEMANTIC))
        results = self.store.search("Python", limit=5)
        assert len(results) >= 1

    def test_search_no_results(self):
        results = self.store.search("xyznonexistent")
        assert len(results) == 0

    # ── Deduplication ─────────────────────────────────────────

    def test_corroboration_on_duplicate(self):
        node1 = MemoryNode.create(content="User prefers dark mode", memory_type=MemoryType.SEMANTIC)
        self.store.add(node1)
        self.db.save_memory(node1)
        initial_count = self.store.count()

        # Add very similar content — should corroborate, not duplicate
        node2 = MemoryNode.create(content="User prefers dark mode", memory_type=MemoryType.SEMANTIC)
        self.store.add(node2)
        assert self.store.count() == initial_count  # Count shouldn't increase

    # ── Knowledge graph operations ────────────────────────────

    def test_get_entities(self):
        self.store.add(MemoryNode.create(content="Entity A", memory_type=MemoryType.SEMANTIC))
        self.store.add(MemoryNode.create(content="Entity B", memory_type=MemoryType.SEMANTIC))
        entities = self.store.get_entities()
        assert len(entities) >= 2

    def test_deprecate_fact(self):
        old = MemoryNode.create(content="Old fact old information", memory_type=MemoryType.SEMANTIC)
        new = MemoryNode.create(content="New fact updated information", memory_type=MemoryType.SEMANTIC)
        self.store.add(old)
        self.store.add(new)
        self.db.save_memory(old)
        self.db.save_memory(new)

        self.store.deprecate_fact(old.id, new.id)
        node = self.store.get(old.id)
        assert node is not None
        assert node.status == MemoryStatus.DEPRECATED

    def test_get_related(self):
        from mnemosynth.core.types import RelationshipEdge
        n1 = MemoryNode.create(content="Python language", memory_type=MemoryType.SEMANTIC)
        n2 = MemoryNode.create(content="Django framework", memory_type=MemoryType.SEMANTIC)
        self.store.add(n1)
        self.store.add(n2)

        edge = RelationshipEdge(source_id=n1.id, target_id=n2.id, relation_type="related_to")
        self.store.add_relationship(edge)

        related = self.store.get_related(n1.id)
        assert len(related) >= 1
