"""Announce queue — buffers subagent results when parent is busy."""

from __future__ import annotations

import asyncio
import time
from dataclasses import dataclass, field
from typing import Callable, Awaitable

from loguru import logger

_DEBOUNCE_SECONDS = 1.0
_DEFAULT_CAP = 20


@dataclass
class AnnounceItem:
    prompt: str
    summary: str     # one-liner for batch display
    enqueued_at: float = field(default_factory=time.time)


class AnnounceQueue:
    """Per-session announce queue with debounce and batching."""

    def __init__(
        self,
        session_key: str,
        send_fn: Callable[[str], Awaitable[None]],
        cap: int = _DEFAULT_CAP,
    ) -> None:
        self.session_key = session_key
        self._send_fn = send_fn
        self._cap = cap
        self.items: list[AnnounceItem] = []
        self._draining = False
        self._last_enqueued = 0.0

    async def enqueue(self, item: AnnounceItem) -> None:
        # Drop oldest if over cap
        if len(self.items) >= self._cap:
            dropped = self.items.pop(0)
            logger.debug(f"[AnnounceQueue] Dropped oldest item: {dropped.summary}")
        self.items.append(item)
        self._last_enqueued = time.time()
        if not self._draining:
            asyncio.create_task(self._drain())

    async def _drain(self) -> None:
        self._draining = True
        try:
            while self.items:
                # Wait for debounce window
                wait = _DEBOUNCE_SECONDS - (time.time() - self._last_enqueued)
                if wait > 0:
                    await asyncio.sleep(wait)
                if not self.items:
                    break

                if len(self.items) == 1:
                    item = self.items.pop(0)
                    await self._send_fn(item.prompt)
                else:
                    # Batch multiple completed tasks into one message
                    items = self.items[:]
                    self.items.clear()
                    summaries = "\n".join(f"- {i.summary}" for i in items)
                    batch_prompt = (
                        f"[{len(items)} background tasks completed]\n"
                        f"{summaries}\n\n"
                        "Briefly summarize these results for the user in 1-2 sentences."
                    )
                    await self._send_fn(batch_prompt)
        except Exception as e:
            logger.error(f"[AnnounceQueue] Drain error for {self.session_key}: {e}")
        finally:
            self._draining = False
            # If items were added while draining, restart
            if self.items:
                asyncio.create_task(self._drain())


# Module-level queue store
_queues: dict[str, AnnounceQueue] = {}


def get_or_create_queue(
    session_key: str,
    send_fn: Callable[[str], Awaitable[None]],
) -> AnnounceQueue:
    if session_key not in _queues:
        _queues[session_key] = AnnounceQueue(session_key, send_fn)
    return _queues[session_key]


def remove_queue(session_key: str) -> None:
    _queues.pop(session_key, None)
