"""Parallel channel polling helper."""

from __future__ import annotations

import asyncio
import logging
from typing import Any, Awaitable, Callable

logger = logging.getLogger(__name__)

# poll_fn signature: async (account, entity, min_id, limit) -> list[ChannelMessage]
PollFn = Callable[..., Awaitable[list[Any]]]


async def _poll_one(
    poll_fn: PollFn, account: str, channel: str, min_id: int, batch_size: int,
) -> tuple[str, list[dict]]:
    """Poll a single channel, return (channel, messages as dicts). Errors → empty list."""
    try:
        raw = await poll_fn(account, channel, min_id=min_id, limit=batch_size)
        # Convert ChannelMessage pydantic models to dicts for downstream processing
        msgs = [m.model_dump() if hasattr(m, "model_dump") else m for m in raw]
        return channel, msgs
    except Exception as e:
        logger.warning("Poll error [%s]: %s", channel, e)
        return channel, []


async def poll_all_channels(
    poll_fn: PollFn,
    account: str,
    offsets: dict[str, int],
    batch_size: int,
    min_text_length: int,
    max_text_length: int,
) -> dict[str, list[dict]]:
    """Poll all channels in parallel, filter by text length, update offsets.

    Returns:
        Dict of channel → filtered messages (as dicts).
    """
    tasks = [
        _poll_one(poll_fn, account, ch, min_id, batch_size)
        for ch, min_id in offsets.items()
    ]
    results = await asyncio.gather(*tasks)

    filtered: dict[str, list[dict]] = {}
    for channel, msgs in results:
        if not msgs:
            continue
        offsets[channel] = msgs[-1]["message_id"]
        text_msgs = [
            m for m in msgs
            if m.get("text")
            and min_text_length <= len(m["text"]) <= max_text_length
        ]
        if text_msgs:
            filtered[channel] = text_msgs

    return filtered
