"""Persistent memory store — the agent's long-term memory across sessions."""

from __future__ import annotations

from agent_scout.db.database import Database
from agent_scout.db.models import Memory
from agent_scout.events import Event, EventBus, EventType


class MemoryStore:
    """Stores and retrieves agent memories with semantic tagging and decay.

    Memories include user preferences, successful strategies,
    frequently used sources, and learned facts.
    """

    def __init__(self, db: Database, event_bus: EventBus | None = None) -> None:
        self._db = db
        self._bus = event_bus

    async def remember(
        self,
        content: str,
        memory_type: str,
        tags: list[str] | None = None,
        relevance_score: float = 1.0,
    ) -> Memory:
        """Store a new memory."""
        memory = Memory(
            content=content,
            memory_type=memory_type,
            tags=tags or [],
            relevance_score=relevance_score,
        )
        await self._db.store_memory(memory)
        if self._bus:
            await self._bus.emit(
                Event(
                    event_type=EventType.MEMORY_STORED,
                    data={"memory_id": memory.id, "type": memory_type, "content": content},
                )
            )
        return memory

    async def recall(
        self,
        memory_type: str | None = None,
        tags: list[str] | None = None,
        limit: int = 10,
    ) -> list[Memory]:
        """Recall memories, optionally filtered by type and tags.

        Automatically updates access counts for recalled memories.
        """
        memories = await self._db.search_memories(memory_type=memory_type, tags=tags, limit=limit)
        # Touch each recalled memory to update access count
        for m in memories:
            await self._db.touch_memory(m.id)
        if self._bus and memories:
            await self._bus.emit(
                Event(
                    event_type=EventType.MEMORY_RECALLED,
                    data={
                        "count": len(memories),
                        "types": list({m.memory_type for m in memories}),
                    },
                )
            )
        return memories

    async def recall_for_task(self, task_description: str) -> list[Memory]:
        """Recall memories relevant to a task description.

        Extracts keywords from the description and searches by tags.
        """
        # Simple keyword extraction — split on spaces, filter short words
        keywords = [w.lower().strip(".,!?\"'") for w in task_description.split() if len(w) > 3]
        if not keywords:
            return []
        return await self.recall(tags=keywords, limit=10)

    async def decay(self, factor: float = 0.95) -> None:
        """Apply memory decay — reduce relevance of all memories.

        Should be called periodically (e.g., once per day or per session).
        """
        await self._db.decay_memories(decay_factor=factor)
