from __future__ import annotations

import pytest

from core.config.settings import RedisSettings
from services.base.redis import RedisService


class _FakeRedisClient:
    def __init__(self) -> None:
        self.closed = False

    async def ping(self) -> bool:
        return True

    async def info(self) -> dict[str, object]:
        return {
            "redis_version": "7.2",
            "connected_clients": 1,
            "used_memory_human": "1M",
            "uptime_in_seconds": 10,
        }

    async def aclose(self) -> None:
        self.closed = True


@pytest.mark.asyncio
async def test_initialize_success(monkeypatch: pytest.MonkeyPatch) -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))

    def _build_client(_: RedisService) -> _FakeRedisClient:
        return _FakeRedisClient()

    monkeypatch.setattr(RedisService, "_build_client", _build_client)

    result = await service.initialize()

    assert result is True
    assert service.is_initialized is True

    health = await service.health_check()
    assert health["status"] == "healthy"


@pytest.mark.asyncio
async def test_initialize_failure(monkeypatch: pytest.MonkeyPatch) -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))

    def _build_client(_: RedisService) -> _FakeRedisClient:
        raise RuntimeError("boom")

    monkeypatch.setattr(RedisService, "_build_client", _build_client)

    result = await service.initialize()

    assert result is False
    assert service.is_initialized is False


@pytest.mark.asyncio
async def test_close_is_idempotent() -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))

    assert await service.close() is True
    assert service.is_initialized is False


@pytest.mark.asyncio
async def test_health_check_uninitialized() -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))

    health = await service.health_check()

    assert health["status"] == "unhealthy"


@pytest.mark.asyncio
async def test_close_closes_client(monkeypatch: pytest.MonkeyPatch) -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))
    client = _FakeRedisClient()

    def _build_client(_: RedisService) -> _FakeRedisClient:
        return client

    monkeypatch.setattr(RedisService, "_build_client", _build_client)

    assert await service.initialize() is True
    assert await service.close() is True
    assert client.closed is True
    assert service.is_initialized is False


def test_get_client_raises_before_init() -> None:
    service = RedisService(settings=RedisSettings(host="localhost", port=6379))

    with pytest.raises(RuntimeError):
        service.get_client()
