"""TTL cache with LRU eviction."""
from __future__ import annotations

import asyncio
import time
from collections import OrderedDict
from typing import Any

_SENTINEL = object()


class AsyncTTLCache:
    """Async LRU cache with per-entry time-to-live."""

    __slots__ = ("_ttl", "_max_size", "_data", "_lock")

    def __init__(self, ttl: float = 30.0, max_size: int = 256) -> None:
        self._ttl = ttl
        self._max_size = max_size
        self._data: OrderedDict[str, tuple[float, Any]] = OrderedDict()
        self._lock = asyncio.Lock()

    async def get(self, key: str) -> Any | None:
        """Get value if present and not expired."""
        async with self._lock:
            entry = self._data.get(key)
            if entry is None:
                return None
            expires_at, value = entry
            if time.monotonic() > expires_at:
                del self._data[key]
                return None
            # Move to end (LRU)
            self._data.move_to_end(key)
            return value

    async def set(self, key: str, value: Any, ttl: float | None = None) -> None:
        """Store value with TTL."""
        async with self._lock:
            effective_ttl = ttl if ttl is not None else self._ttl
            self._data[key] = (time.monotonic() + effective_ttl, value)
            self._data.move_to_end(key)
            # Evict oldest if over capacity
            while len(self._data) > self._max_size:
                self._data.popitem(last=False)

    async def delete(self, key: str) -> bool:
        """Remove entry. Returns True if existed."""
        async with self._lock:
            if key in self._data:
                del self._data[key]
                return True
            return False

    async def clear(self) -> None:
        """Remove all entries."""
        async with self._lock:
            self._data.clear()

    async def cleanup_expired(self) -> int:
        """Remove all expired entries. Returns count removed."""
        async with self._lock:
            now = time.monotonic()
            expired_keys = [k for k, (exp, _) in self._data.items() if now > exp]
            for key in expired_keys:
                del self._data[key]
            return len(expired_keys)

    @property
    def size(self) -> int:
        return len(self._data)
