"""
Redis connection client for caching.

Provides async Redis client with connection pooling for
position ratings and other cached data.

Author: Claude
Date: 2025-11-03
Phase: 3E-Final
"""

import logging

import redis.asyncio as redis
from redis.asyncio import Redis
from redis.exceptions import RedisError

logger = logging.getLogger(f"{__name__}.RedisClient")


class RedisClient:
    """
    Async Redis client with connection pooling.

    Singleton pattern - use redis_client instance.
    """

    def __init__(self):
        self._redis: Redis | None = None
        self._url: str | None = None

    async def connect(self, redis_url: str = "redis://localhost:6379/0") -> None:
        """
        Connect to Redis server.

        Args:
            redis_url: Redis connection URL
                Format: redis://host:port/db
                Example: redis://localhost:6379/0
        """
        if self._redis is not None:
            logger.warning("Redis client already connected")
            return

        try:
            self._url = redis_url
            self._redis = await redis.from_url(
                redis_url,
                encoding="utf-8",
                decode_responses=True,
                max_connections=10,  # Connection pool size
            )

            # Test connection
            await self._redis.ping()
            logger.info(f"Redis connected successfully: {redis_url}")

        except RedisError as e:
            logger.error(f"Failed to connect to Redis at {redis_url}: {e}")
            self._redis = None
            raise

    async def disconnect(self) -> None:
        """Disconnect from Redis server."""
        if self._redis is not None:
            await self._redis.close()
            await self._redis.connection_pool.disconnect()
            self._redis = None
            logger.info("Redis disconnected")

    @property
    def client(self) -> Redis:
        """
        Get Redis client instance.

        Returns:
            Redis client

        Raises:
            RuntimeError: If not connected
        """
        if self._redis is None:
            raise RuntimeError(
                "Redis client not connected. "
                "Call await redis_client.connect() first."
            )
        return self._redis

    @property
    def is_connected(self) -> bool:
        """Check if Redis is connected."""
        return self._redis is not None

    async def ping(self) -> bool:
        """
        Test Redis connection.

        Returns:
            True if Redis is responding, False otherwise
        """
        if not self.is_connected:
            return False

        try:
            await self._redis.ping()
            return True
        except RedisError as e:
            logger.error(f"Redis ping failed: {e}")
            return False


# Singleton instance
redis_client = RedisClient()
