"""In-memory TTLCache implementation using cachetools.

Provides a thread-safe, TTL-based cache for storing API responses.
"""

from __future__ import annotations

import logging
import threading
from typing import Any, Generic, TypeVar

from cachetools import TTLCache

from indiaopt.config.settings import Settings, get_settings
from indiaopt.constants import (
    DEFAULT_CACHE_TTL_S,
    DEFAULT_EXPIRY_CACHE_TTL_S,
)

logger = logging.getLogger("indiaopt.cache")

T = TypeVar("T")


class MemoryCache(Generic[T]):
    """Thread-safe TTL in-memory cache.

    Wraps :class:`cachetools.TTLCache` with a thread lock.

    Args:
        maxsize: Maximum number of items the cache can hold.
        ttl:     Time-to-live for each item in seconds.
    """

    def __init__(self, maxsize: int = 1000, ttl: float = 60.0) -> None:
        self._cache: TTLCache[str, T] = TTLCache(maxsize=maxsize, ttl=ttl)
        self._lock = threading.Lock()
        self.ttl = ttl

    def get(self, key: str) -> T | None:
        """Get an item from the cache. Returns ``None`` if expired or missing."""
        with self._lock:
            return self._cache.get(key)

    def set(self, key: str, value: T) -> None:
        """Set an item in the cache."""
        with self._lock:
            self._cache[key] = value

    def delete(self, key: str) -> None:
        """Delete an item from the cache."""
        with self._lock:
            self._cache.pop(key, None)

    def clear(self) -> None:
        """Clear all items from the cache."""
        with self._lock:
            self._cache.clear()

    @property
    def currsize(self) -> int:
        """Current number of items in the cache."""
        with self._lock:
            return int(self._cache.currsize)


# Module-level default caches
_chain_cache: MemoryCache[Any] | None = None
_chain_cache_lock = threading.Lock()

_expiry_cache: MemoryCache[list[str]] | None = None
_expiry_cache_lock = threading.Lock()


def get_chain_cache(settings: Settings | None = None) -> MemoryCache[Any]:
    """Return the global option-chain TTL cache."""
    global _chain_cache
    with _chain_cache_lock:
        if _chain_cache is None:
            s = settings or get_settings()
            ttl = getattr(s, "cache_ttl", DEFAULT_CACHE_TTL_S)
            _chain_cache = MemoryCache(maxsize=1000, ttl=ttl)
    return _chain_cache


def get_expiry_cache(settings: Settings | None = None) -> MemoryCache[list[str]]:
    """Return the global expiry-dates TTL cache."""
    global _expiry_cache
    with _expiry_cache_lock:
        if _expiry_cache is None:
            s = settings or get_settings()
            ttl = getattr(s, "expiry_cache_ttl", DEFAULT_EXPIRY_CACHE_TTL_S)
            _expiry_cache = MemoryCache(maxsize=500, ttl=ttl)
    return _expiry_cache


__all__ = ["MemoryCache", "get_chain_cache", "get_expiry_cache"]
