from datetime import UTC, datetime

import pytest

from src.services.operator_summary_cache import (
    clear_operator_summary_cache,
    get_cached_operator_summary_async,
    get_cached_operator_summary,
    store_operator_summary_async,
    store_operator_summary,
)


class _FakeRedis:
    def __init__(self) -> None:
        self.values: dict[str, str] = {}
        self.expirations: dict[str, int] = {}

    async def get(self, key: str) -> str | None:
        return self.values.get(key)

    async def set(self, key: str, value: str, ex: int) -> bool:
        self.values[key] = value
        self.expirations[key] = ex
        return True

    async def delete(self, key: str) -> int:
        return 1 if self.values.pop(key, None) is not None else 0


def test_operator_summary_cache_returns_copy_with_hit_metadata() -> None:
    clear_operator_summary_cache()
    key = {"project_id": "awoooi", "limit": 30}
    stored = store_operator_summary(
        "truth_chain_quality_summary",
        key,
        {"evaluated_total": 30, "nested": {"ok": True}},
        ttl_seconds=30,
        now_monotonic=100.0,
        now_utc=datetime(2026, 6, 1, tzinfo=UTC),
    )

    assert stored["cache"]["status"] == "miss"
    stored["nested"]["ok"] = False

    cached = get_cached_operator_summary(
        "truth_chain_quality_summary",
        key,
        ttl_seconds=30,
        now_monotonic=105.5,
    )

    assert cached is not None
    assert cached["cache"]["status"] == "hit"
    assert cached["cache"]["age_seconds"] == 5.5
    assert cached["nested"]["ok"] is True


def test_operator_summary_cache_expires_by_ttl() -> None:
    clear_operator_summary_cache()
    key = {"project_id": "awoooi", "page": 1}
    store_operator_summary(
        "callback_replies",
        key,
        {"total": 4},
        ttl_seconds=20,
        now_monotonic=200.0,
        now_utc=datetime(2026, 6, 1, tzinfo=UTC),
    )


@pytest.mark.asyncio
async def test_operator_summary_cache_uses_shared_redis(monkeypatch) -> None:
    clear_operator_summary_cache()
    fake_redis = _FakeRedis()
    monkeypatch.setattr("src.core.redis_client.get_redis", lambda: fake_redis)
    key = {"project_id": "awoooi", "per_page": 1}

    stored = await store_operator_summary_async(
        "callback_replies",
        key,
        {"total": 4, "items": []},
        ttl_seconds=20,
        now_monotonic=300.0,
        now_utc=datetime(2026, 6, 1, tzinfo=UTC),
    )

    assert stored["cache"]["status"] == "miss"
    assert fake_redis.values

    clear_operator_summary_cache()
    cached = await get_cached_operator_summary_async(
        "callback_replies",
        key,
        ttl_seconds=20,
        now_monotonic=302.0,
    )

    assert cached is not None
    assert cached["cache"]["status"] == "hit"
    assert cached["total"] == 4

    assert (
        get_cached_operator_summary(
            "callback_replies",
            key,
            ttl_seconds=20,
            now_monotonic=220.0,
        )
        is None
    )
