from __future__ import annotations

import logging
import os

import redis.asyncio as aioredis

from config import REDIS_HOST, REDIS_PASSWORD, REDIS_PORT, REDIS_USERNAME

logger = logging.getLogger(__name__)


class RedisClient:
    """
    Singleton Class quản lý Redis Client.
    """

    def __init__(self):
        self._client: aioredis.Redis | None = None

    async def initialize(self, skip_ping: bool = False) -> aioredis.Redis:
        """
        Initialize async Redis client - call in startup

        Args:
            skip_ping: Nếu True, skip ping test (tốt cho dev mode để tăng tốc reload)
        """
        if self._client is not None:
            return self._client

        # Try URL format first if available
        redis_url = os.getenv("REDIS_URL")

        try:
            # Trong dev mode, giảm timeout để không block quá lâu
            is_dev = os.getenv("SKIP_LLM_WARMUP", "false").lower() == "true"
            connect_timeout = 3 if is_dev else 10  # Dev: 3s, Production: 10s

            if redis_url:
                logger.info("🔌 Connecting to Redis via URL...")
                self._client = aioredis.from_url(
                    redis_url, decode_responses=True, socket_connect_timeout=connect_timeout
                )
            else:
                # Build connection kwargs
                logger.info(f"🔌 Connecting to Redis at {REDIS_HOST}:{REDIS_PORT}")
                connection_kwargs = {
                    "host": REDIS_HOST,
                    "port": REDIS_PORT,
                    "decode_responses": True,
                    "socket_connect_timeout": connect_timeout,
                }

                # Add password if provided
                if REDIS_PASSWORD:
                    connection_kwargs["password"] = REDIS_PASSWORD

                # Add username if provided (for Redis ACL)
                if REDIS_USERNAME:
                    connection_kwargs["username"] = REDIS_USERNAME

                self._client = aioredis.Redis(**connection_kwargs)

            # Test connection (skip trong dev mode để tăng tốc)
            if skip_ping is False:
                # Type: ignore vì linter có thể hiểu nhầm
                await self._client.ping()  # type: ignore
                logger.info("✅ Redis connected successfully")
            else:
                logger.info("✅ Redis client created (ping skipped for faster reload)")
            return self._client

        except Exception as e:
            logger.error(f"❌ Failed to connect to Redis: {e}")
            raise

    async def close(self) -> None:
        """Close Redis client - call in shutdown"""
        if self._client is not None:
            await self._client.close()
            self._client = None
            logger.info("✅ Redis connection closed")

    def get_client(self) -> aioredis.Redis:
        """
        Get Redis client - lazy init nếu chưa có.

        CÁCH HOẠT ĐỘNG:
        1. Lần đầu gọi → self._client = None → tự động tạo → lưu cache
        2. Lần sau gọi → self._client đã có → dùng cache → không tạo lại

        CÓ THỂ BỎ LIFESPAN:
        - Có! Không cần init trong lifespan
        - Client sẽ tự động tạo khi cần (lần đầu gọi get_redis())
        - Sau đó cache lại, lần sau dùng cache

        NOTE: Lazy init có thể làm lần đầu request chậm hơn một chút (~10-50ms)
        """
        if self._client is None:
            # Lazy init: tự động tạo client nếu chưa có
            logger.info("⚡ Redis client lazy init (creating on first use)")
            redis_url = os.getenv("REDIS_URL")
            is_dev = os.getenv("SKIP_LLM_WARMUP", "false").lower() == "true"
            connect_timeout = 3 if is_dev else 10

            if redis_url:
                self._client = aioredis.from_url(
                    redis_url, decode_responses=True, socket_connect_timeout=connect_timeout
                )
            else:
                connection_kwargs = {
                    "host": REDIS_HOST,
                    "port": REDIS_PORT,
                    "decode_responses": True,
                    "socket_connect_timeout": connect_timeout,
                }
                if REDIS_PASSWORD:
                    connection_kwargs["password"] = REDIS_PASSWORD
                if REDIS_USERNAME:
                    connection_kwargs["username"] = REDIS_USERNAME
                self._client = aioredis.Redis(**connection_kwargs)
            logger.info("✅ Redis client created (lazy init)")
        return self._client


# --- Singleton Instance & Public API ---

_redis_manager = RedisClient()

init_redis = _redis_manager.initialize
close_redis = _redis_manager.close
get_redis = _redis_manager.get_client
