"""
Redis client with connection pooling
"""
import redis.asyncio as redis
from typing import Optional, Any
import json
import structlog
from config import settings

logger = structlog.get_logger()

class RedisClient:
    """Async Redis client wrapper"""

    def __init__(self):
        self._pool: Optional[redis.ConnectionPool] = None
        self._client: Optional[redis.Redis] = None

    async def connect(self):
        """Initialize Redis connection pool"""
        try:
            logger.info("redis_connecting", host=settings.REDIS_HOST, port=settings.REDIS_PORT)

            self._pool = redis.ConnectionPool.from_url(
                settings.redis_url,
                max_connections=settings.REDIS_MAX_CONNECTIONS,
                decode_responses=True,
            )

            self._client = redis.Redis(connection_pool=self._pool)

            # Test connection
            await self._client.ping()

            logger.info("redis_connected")
        except Exception as e:
            logger.error("redis_connection_failed", error=str(e))
            raise

    async def close(self):
        """Close Redis connections"""
        try:
            if self._client:
                await self._client.close()
            if self._pool:
                await self._pool.disconnect()
            logger.info("redis_closed")
        except Exception as e:
            logger.error("redis_close_failed", error=str(e))

    async def get(self, key: str) -> Optional[str]:
        """Get value by key"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.get(key)

    async def set(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
        """Set value with optional expiration (seconds)"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.set(key, value, ex=expire)

    async def delete(self, key: str) -> int:
        """Delete key"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.delete(key)

    async def exists(self, key: str) -> bool:
        """Check if key exists"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.exists(key) > 0

    async def get_json(self, key: str) -> Optional[dict]:
        """Get JSON value"""
        value = await self.get(key)
        if value:
            return json.loads(value)
        return None

    async def set_json(self, key: str, value: dict, expire: Optional[int] = None) -> bool:
        """Set JSON value"""
        return await self.set(key, json.dumps(value), expire)

    async def get_many(self, keys: list[str]) -> list[Optional[str]]:
        """Get multiple values"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.mget(keys)

    async def set_many(self, mapping: dict[str, Any]) -> bool:
        """Set multiple key-value pairs"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.mset(mapping)

    async def incr(self, key: str, amount: int = 1) -> int:
        """Increment value"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.incrby(key, amount)

    async def expire(self, key: str, seconds: int) -> bool:
        """Set expiration on key"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.expire(key, seconds)

    async def ttl(self, key: str) -> int:
        """Get time to live for key"""
        if not self._client:
            raise RuntimeError("Redis client not connected")
        return await self._client.ttl(key)

# Global Redis client instance
redis_client = RedisClient()

# Convenience functions
async def init_redis():
    """Initialize Redis connection (call on startup)"""
    await redis_client.connect()

async def close_redis():
    """Close Redis connection (call on shutdown)"""
    await redis_client.close()
