import os
from typing import Optional, TYPE_CHECKING

from .redis import RedisCacheClient
from .memory import MemoryCacheClient

if TYPE_CHECKING:
    from ..serializer import Serializer


DEFAULT_REDIS_PREFIX = "REDIS"
REDIS_URL_KEYS = ["REDIS_URL", "REDIS_DSN", "CACHE_URL"]


def _resolve_redis_url(env_prefix: str = DEFAULT_REDIS_PREFIX) -> Optional[str]:
    """Build a Redis URL from environment variables."""
    for key in REDIS_URL_KEYS:
        value = os.getenv(key)
        if value:
            return value

    host = os.getenv(f"{env_prefix}_HOST", "localhost")
    port = os.getenv(f"{env_prefix}_PORT", "6379")
    db = os.getenv(f"{env_prefix}_DB", "0")
    password = os.getenv(f"{env_prefix}_PASSWORD")

    auth = f":{password}@" if password else ""
    return f"redis://{auth}{host}:{port}/{db}"


def create_redis_cache_client(
    url: Optional[str] = None,
    serializer: "Serializer | None" = None,
    env_prefix: str = DEFAULT_REDIS_PREFIX,
    **kwargs,
) -> RedisCacheClient:
    """Create a configured Redis cache client.

    The factory first uses an explicit *url* value.  If none is provided it
    falls back to environment variables:

    * ``REDIS_URL``, ``REDIS_DSN``, ``CACHE_URL`` — full connection URL.
    * ``{PREFIX}_HOST``, ``{PREFIX}_PORT``, ``{PREFIX}_DB``,
      ``{PREFIX}_PASSWORD`` — individual components (default prefix: ``REDIS``).

    Parameters
    ----------
    url:
        Explicit Redis URL (``redis://…``).
    serializer:
        Optional :class:`~cache_core.serializer.Serializer`.
    env_prefix:
        Environment variable prefix for component-based resolution.
    **kwargs:
        Forwarded to :class:`redis.asyncio.Redis`.
    """
    connection_url = url or _resolve_redis_url(env_prefix)
    if not connection_url:
        raise ValueError(
            "No Redis URL configured. Provide a `url` or set environment variables: "
            "REDIS_URL, REDIS_DSN, CACHE_URL, or REDIS_HOST/REDIS_PORT/REDIS_DB/REDIS_PASSWORD."
        )
    return RedisCacheClient(connection_url, serializer=serializer, **kwargs)


def get_redis_cache_client(
    url: Optional[str] = None,
    serializer: "Serializer | None" = None,
    env_prefix: str = DEFAULT_REDIS_PREFIX,
    **kwargs,
) -> RedisCacheClient:
    """Alias for :func:`create_redis_cache_client`."""
    return create_redis_cache_client(
        url=url, serializer=serializer, env_prefix=env_prefix, **kwargs
    )


def create_memory_cache_client(
    serializer: "Serializer | None" = None,
) -> MemoryCacheClient:
    """Create an in-process memory cache client (no external dependencies)."""
    return MemoryCacheClient(serializer=serializer)


def get_memory_cache_client(
    serializer: "Serializer | None" = None,
) -> MemoryCacheClient:
    """Alias for :func:`create_memory_cache_client`."""
    return create_memory_cache_client(serializer=serializer)
