"""Agent connectivity counts and filters — Redis overlay per DB server (not global key scan)."""

from __future__ import annotations

from typing import Any

from sqlalchemy import and_, or_, select

from server.domain.models import Server
from server.infrastructure.database.server_repo import _target_path_unset_filter

REDIS_KEY_PREFIX = "heartbeat:"


def heartbeat_indicates_online(heartbeat: dict[str, Any] | None) -> bool:
    """True when Redis heartbeat hash exists and is_online is True (same as stats/list)."""
    return bool(heartbeat) and heartbeat.get("is_online") == "True"


def monitored_server_filter():
    """Servers expected to run Nexus Agent (API key or version on file)."""
    return or_(
        and_(Server.agent_api_key.isnot(None), Server.agent_api_key != ""),
        and_(Server.agent_version.isnot(None), Server.agent_version != ""),
    )


def item_matches_online_filter(item: dict[str, Any], want_online: bool) -> bool:
    """Match UI status chip: online vs offline (excludes unknown)."""
    status = item.get("status") or "unknown"
    if want_online:
        return status == "online"
    return status == "offline"


async def count_monitored_connectivity(
    redis: Any,
    session: Any,
    *,
    exclude_unset_target_path: bool = False,
    batch_size: int = 200,
) -> dict[str, int]:
    """Count online/offline among Agent-monitored servers using per-id Redis heartbeats."""
    filters = [monitored_server_filter()]
    if exclude_unset_target_path:
        filters.append(_target_path_unset_filter(False))

    result = await session.execute(select(Server.id).where(*filters))
    ids = [int(row[0]) for row in result.all()]
    monitored = len(ids)
    if not monitored:
        return {"monitored": 0, "online": 0, "offline": 0}

    online = 0
    offline = 0
    for i in range(0, len(ids), batch_size):
        chunk = ids[i : i + batch_size]
        pipe = redis.pipeline()
        for sid in chunk:
            pipe.hgetall(f"{REDIS_KEY_PREFIX}{sid}")
        heartbeats = await pipe.execute()
        for hb in heartbeats:
            if heartbeat_indicates_online(hb):
                online += 1
            else:
                offline += 1

    return {"monitored": monitored, "online": online, "offline": offline}
