"""Memory tool — search, save, and forget facts about the user."""

from navi.memory.store import MemoryStore
from navi.tools.base import current_session_id

from .base import Tool, ToolResult

_VALID_CATEGORIES = {"profile", "preferences", "technical", "projects", "other"}


class MemoryTool(Tool):
    name = "memory"
    description = (
        "Manage long-term memory about the user — facts that survive across sessions. "
        "Actions: save (upsert a fact), search (find facts by query), forget (delete by key), list (all facts)."
    )
    parameters = {
        "type": "object",
        "properties": {
            "action": {
                "type": "string",
                "enum": ["save", "search", "forget", "list"],
                "description": (
                    "save — upsert a fact (overwrites existing key). "
                    "search — find facts by keyword query. "
                    "forget — delete a fact by key. "
                    "list — return all stored facts."
                ),
            },
            "query": {
                "type": "string",
                "description": "search only: keywords describing what to look for.",
            },
            "category": {
                "type": "string",
                "enum": ["profile", "preferences", "technical", "projects", "other"],
                "description": (
                    "save/forget: fact category. "
                    "profile=who they are, preferences=likes/dislikes, "
                    "technical=OS/tools/servers, projects=ongoing work, other=anything else."
                ),
            },
            "key": {
                "type": "string",
                "description": (
                    "save/forget: snake_case identifier unique within the category. "
                    "Examples: name, primary_os, home_server_ip, response_language."
                ),
            },
            "value": {
                "type": "string",
                "description": "save only: the fact as a concise plain-text statement.",
            },
        },
        "required": ["action"],
    }

    def __init__(self, memory_store: MemoryStore) -> None:
        self._store = memory_store

    async def execute(self, params: dict) -> ToolResult:
        action = params.get("action", "")

        if action == "save":
            return await self._save(params)
        if action == "search":
            return await self._search(params)
        if action == "forget":
            return await self._forget(params)
        if action == "list":
            return await self._list()
        return ToolResult(success=False, output=f"Unknown action '{action}'.", error="invalid action")

    async def _save(self, params: dict) -> ToolResult:
        category = (params.get("category") or "").strip().lower()
        key = (params.get("key") or "").strip()
        value = (params.get("value") or "").strip()

        if not category:
            return ToolResult(success=False, output="category is required for save.", error="missing category")
        if category not in _VALID_CATEGORIES:
            return ToolResult(
                success=False,
                output=f"Invalid category '{category}'. Must be one of: {', '.join(sorted(_VALID_CATEGORIES))}",
                error="invalid category",
            )
        if not key:
            return ToolResult(success=False, output="key is required for save.", error="missing key")
        if not value:
            return ToolResult(success=False, output="value is required for save.", error="missing value")

        session_id = current_session_id.get(None)
        await self._store.upsert_fact(category, key, value, session_id)
        return ToolResult(success=True, output=f"Saved [{category}] {key}: {value}")

    async def _search(self, params: dict) -> ToolResult:
        query = (params.get("query") or "").strip()
        if not query:
            return ToolResult(success=False, output="query is required for search.", error="missing query")

        facts = await self._store.search_facts(query, limit=15)
        if not facts:
            return ToolResult(success=True, output="No matching facts found in memory.")

        lines = [f"[{f['category']}] {f['key']}: {f['value']}" for f in facts]
        return ToolResult(success=True, output=f"Found {len(facts)} fact(s):\n" + "\n".join(lines))

    async def _forget(self, params: dict) -> ToolResult:
        key = (params.get("key") or "").strip()
        category = (params.get("category") or "").strip() or None

        if not key:
            return ToolResult(success=False, output="key is required for forget.", error="missing key")

        deleted = await self._store.delete_fact(key, category)
        if deleted == 0:
            return ToolResult(success=False, output=f"No fact found with key '{key}'.", error="not found")

        noun = "fact" if deleted == 1 else "facts"
        return ToolResult(success=True, output=f"Deleted {deleted} {noun} with key '{key}'.")

    async def _list(self) -> ToolResult:
        facts = await self._store.get_all_facts()
        if not facts:
            return ToolResult(success=True, output="Memory is empty.")

        lines = [f"[{f['category']}] {f['key']}: {f['value']}" for f in facts]
        return ToolResult(success=True, output=f"{len(facts)} fact(s) in memory:\n" + "\n".join(lines))
