"""
StreamOutput - 流式输出封装
"""

import json
from datetime import datetime, timezone
from typing import Any, AsyncGenerator, Callable

from dataclasses import dataclass


@dataclass
class StreamEvent:
    """流式事件"""

    type: str  # "output" | "error" | "status" | "complete"
    session_id: str
    data: str
    timestamp: str


class StreamOutput:
    """流式输出处理器"""

    def __init__(
        self,
        session_id: str,
        websocket_sender: Callable[[str, str], Any] | None = None,
    ):
        self.session_id = session_id
        self.websocket_sender = websocket_sender
        self._listeners: list[Callable[[StreamEvent], Any]] = []

    def add_listener(self, listener: Callable[[StreamEvent], Any]):
        """添加事件监听器"""
        self._listeners.append(listener)

    def remove_listener(self, listener: Callable[[StreamEvent], Any]):
        """移除事件监听器"""
        if listener in self._listeners:
            self._listeners.remove(listener)

    async def push(self, event_type: str, data: str):
        """推送事件到 WebSocket 和监听器"""
        event = StreamEvent(
            type=event_type,
            session_id=self.session_id,
            data=data,
            timestamp=datetime.now(timezone.utc).isoformat(),
        )

        # 发送到 WebSocket
        if self.websocket_sender:
            try:
                await self.websocket_sender(self.session_id, json.dumps(event.__dict__))
            except Exception:
                pass

        # 通知监听器
        for listener in self._listeners:
            try:
                result = listener(event)
                if hasattr(result, "__await__"):
                    await result
            except Exception:
                pass

    async def stream_execution(
        self,
        executor,
        prompt: str,
    ) -> AsyncGenerator[str, None]:
        """包装执行器，实现流式输出"""
        async for line in executor.execute(prompt):
            await self.push("output", line)
            yield line

        await self.push("complete", "")

    async def push_status(self, status: str):
        """推送状态消息"""
        await self.push("status", status)

    async def push_error(self, error: str):
        """推送错误消息"""
        await self.push("error", error)
