"""Session-scoped local cache for retrieved skills and tools.

Simple in-memory cache that lives for the duration of a session.
Cleared on session start and session end to ensure fresh data.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any

from promethian.core.types import Skill, Tool


@dataclass
class CacheEntry:
    """A cached item with metadata."""
    item: Skill | Tool
    retrieved_at: datetime = field(default_factory=datetime.utcnow)
    query_id: str | None = None


class LocalCache:
    """
    Session-scoped cache for skills and tools.

    Lifecycle:
    1. Session starts → cache is cleared
    2. Items retrieved → cached by ID
    3. Same item requested → returned from cache
    4. Session ends → cache is cleared

    This ensures:
    - Fresh data for each task
    - No stale success rates
    - Fast repeated access within a session
    """

    def __init__(self):
        self._skills: dict[str, CacheEntry] = {}
        self._tools: dict[str, CacheEntry] = {}
        self._session_id: str | None = None

    def on_session_start(self, session_id: str) -> None:
        """Clear cache when a new session starts."""
        self._skills.clear()
        self._tools.clear()
        self._session_id = session_id

    def on_session_end(self) -> None:
        """Clear cache when session ends."""
        self._skills.clear()
        self._tools.clear()
        self._session_id = None

    # ============================================
    # SKILLS
    # ============================================

    def get_skill(self, skill_id: str) -> Skill | None:
        """Get a skill from cache if available."""
        entry = self._skills.get(skill_id)
        return entry.item if entry else None

    def put_skill(self, skill: Skill, query_id: str | None = None) -> None:
        """Add a skill to the cache."""
        self._skills[skill.id] = CacheEntry(
            item=skill,
            query_id=query_id,
        )

    def put_skills(self, skills: list[Skill], query_id: str | None = None) -> None:
        """Add multiple skills to the cache."""
        for skill in skills:
            self.put_skill(skill, query_id)

    def get_skill_query_id(self, skill_id: str) -> str | None:
        """Get the query_id used to retrieve a skill."""
        entry = self._skills.get(skill_id)
        return entry.query_id if entry else None

    # ============================================
    # TOOLS
    # ============================================

    def get_tool(self, tool_id: str) -> Tool | None:
        """Get a tool from cache if available."""
        entry = self._tools.get(tool_id)
        return entry.item if entry else None

    def put_tool(self, tool: Tool, query_id: str | None = None) -> None:
        """Add a tool to the cache."""
        self._tools[tool.id] = CacheEntry(
            item=tool,
            query_id=query_id,
        )

    def put_tools(self, tools: list[Tool], query_id: str | None = None) -> None:
        """Add multiple tools to the cache."""
        for tool in tools:
            self.put_tool(tool, query_id)

    def get_tool_query_id(self, tool_id: str) -> str | None:
        """Get the query_id used to retrieve a tool."""
        entry = self._tools.get(tool_id)
        return entry.query_id if entry else None

    # ============================================
    # STATS
    # ============================================

    @property
    def skill_count(self) -> int:
        """Number of cached skills."""
        return len(self._skills)

    @property
    def tool_count(self) -> int:
        """Number of cached tools."""
        return len(self._tools)

    @property
    def is_active(self) -> bool:
        """Whether there's an active session."""
        return self._session_id is not None

    def stats(self) -> dict[str, Any]:
        """Get cache statistics."""
        return {
            "session_id": self._session_id,
            "skills_cached": self.skill_count,
            "tools_cached": self.tool_count,
            "is_active": self.is_active,
        }
