"""Redis caching service with configurable TTLs per data category."""
import json
import logging
from typing import Any

import redis.asyncio as redis

from app.config import settings

logger = logging.getLogger(__name__)

# TTL mapping by category
TTL_MAP = {
    "search": settings.cache_ttl_search,        # 24h
    "detail": settings.cache_ttl_detail,         # 3 days
    "interaction": settings.cache_ttl_interaction,  # 7 days
    "ai": settings.cache_ttl_ai,                 # 30 days
}


class CacheService:
    """Async Redis cache with category-based TTL."""

    def __init__(self, redis_client: redis.Redis | None = None):
        self._redis = redis_client

    @classmethod
    async def create(cls) -> "CacheService":
        """Factory that connects to Redis. Returns a no-op cache on failure."""
        try:
            client = redis.from_url(settings.redis_url, decode_responses=True)
            await client.ping()
            return cls(redis_client=client)
        except Exception:
            logger.warning("Redis unavailable -- caching disabled")
            return cls(redis_client=None)

    async def get(self, key: str) -> Any | None:
        if not self._redis:
            return None
        try:
            raw = await self._redis.get(key)
            return json.loads(raw) if raw else None
        except Exception:
            logger.warning("Cache GET failed for %s", key)
            return None

    async def set(self, key: str, value: Any, ttl_category: str = "search") -> None:
        if not self._redis:
            return
        ttl = TTL_MAP.get(ttl_category, 86400)
        try:
            await self._redis.set(key, json.dumps(value, default=str), ex=ttl)
        except Exception:
            logger.warning("Cache SET failed for %s", key)

    async def delete(self, key: str) -> None:
        if not self._redis:
            return
        try:
            await self._redis.delete(key)
        except Exception:
            logger.warning("Cache DELETE failed for %s", key)

    async def close(self) -> None:
        if self._redis:
            await self._redis.close()
