import time
from collections import OrderedDict
from typing import Any


class TTLCache:
    """TTL-aware LRU cache for single-threaded asyncio use.

    Items expire after `ttl` seconds. When the cache exceeds `max_size`,
    the least-recently-used item is evicted. Not thread-safe — intended
    for use within a single asyncio event loop (no concurrent mutation).
    """

    def __init__(self, max_size: int = 1000, ttl: int = 3600):
        self._store: OrderedDict[str, tuple[Any, float]] = OrderedDict()
        self._max_size = max_size
        self._ttl = ttl

    def get(self, key: str) -> Any | None:
        if key not in self._store:
            return None
        value, ts = self._store[key]
        if time.monotonic() - ts > self._ttl:
            del self._store[key]
            return None
        self._store.move_to_end(key)
        return value

    def set(self, key: str, value: Any) -> None:
        if key in self._store:
            self._store.move_to_end(key)
        self._store[key] = (value, time.monotonic())
        while len(self._store) > self._max_size:
            self._store.popitem(last=False)

    def clear(self) -> None:
        self._store.clear()

    def __len__(self) -> int:
        return len(self._store)
