from __future__ import annotations

import inspect
from typing import Any, Dict, Optional

import redis.asyncio as redis

from core.config.settings import RedisSettings, config

from .service_interface import BaseServiceProvider, register_service_instance


class RedisService(BaseServiceProvider):
    def __init__(self, settings: RedisSettings | None = None) -> None:
        super().__init__("redis")
        self._settings = settings or config.redis
        self._client: Optional[redis.Redis] = None

    def _build_client(self) -> redis.Redis:
        return redis.from_url(
            self._settings.url,
            decode_responses=True,
            socket_connect_timeout=self._settings.socket_connect_timeout,
            socket_timeout=self._settings.socket_timeout,
            max_connections=self._settings.max_connections,
        )

    def _require_client(self) -> redis.Redis:
        client = self._client
        if client is None:
            raise RuntimeError("Redis client is not initialized")
        return client

    async def initialize(self, **_: Any) -> bool:
        try:
            client = self._build_client()
            ping_result = client.ping()
            if inspect.isawaitable(ping_result):
                await ping_result
            self._client = client
            self._set_initialized(True)
            self.logger.info("Redis service initialized")
            return True
        except Exception as exc:  # noqa: BLE001
            self.logger.warning("Redis service initialization failed", error=str(exc))
            self._client = None
            self._set_initialized(False)
            return False

    async def close(self) -> bool:
        client = self._client
        if client is None:
            return True
        try:
            await client.aclose()
            self.logger.info("Redis service closed")
            self._client = None
            self._set_initialized(False)
            return True
        except Exception as exc:  # noqa: BLE001
            self.logger.exception("Redis service close failed", error=str(exc))
            return False

    async def health_check(self) -> Dict[str, Any]:
        client = self._client
        if client is None:
            return {"status": "unhealthy", "details": {"error": "not initialized"}}
        try:
            ping_result = client.ping()
            ping = (
                await ping_result if inspect.isawaitable(ping_result) else ping_result
            )
            info_result = client.info()
            info = (
                await info_result if inspect.isawaitable(info_result) else info_result
            )
            return {
                "status": "healthy" if ping else "unhealthy",
                "details": {
                    "ping": ping,
                    "redis_version": info.get("redis_version"),
                    "connected_clients": info.get("connected_clients"),
                    "used_memory": info.get("used_memory_human"),
                    "uptime_in_seconds": info.get("uptime_in_seconds"),
                },
            }
        except Exception as exc:  # noqa: BLE001
            self.logger.warning("Redis health check failed", error=str(exc))
            return {"status": "unhealthy", "details": {"error": str(exc)}}

    def get_client(self) -> redis.Redis:
        return self._require_client()


redis_service: RedisService = register_service_instance("redis", RedisService())

__all__ = ["RedisService", "redis_service"]
