import asyncio

class Stream:
    __slots__ = ('_send', '_headers', '_closed')

    def __init__(self, send):
        self._send = send
        self._headers = []
        self._closed = False

    def cookie(self, name, value, **opts):
        parts = [f"{name}={value}"]
        for k, v in opts.items():
            k = k.replace("_", "-")
            if isinstance(v, bool):
                if v: parts.append(k)
            else: parts.append(f"{k}={v}")
        self._headers.append([b"set-cookie", "; ".join(parts).encode()])
        return self

    async def open(self):
        headers = [
            [b"content-type", b"text/event-stream"],
            [b"cache-control", b"no-cache"],
            [b"connection", b"keep-alive"],
            [b"x-accel-buffering", b"no"],
        ] + self._headers
        await self._send({"type": "http.response.start", "status": 200, "headers": headers})

    async def send_event(self, data):
        "Send a pre-formatted SSE event string (from html-tags sse module)"
        if self._closed: return
        try:
            await self._send({"type": "http.response.body", "body": data.encode(), "more_body": True})
        except Exception:
            self._closed = True

    async def keepalive(self):
        "Send an SSE comment to keep the connection alive"
        await self.send_event(":\n\n")

    async def close(self):
        if self._closed: return
        self._closed = True
        await self._send({"type": "http.response.body", "body": b""})

    async def alive(self, events, timeout=30):
        "Yield relay events while keeping the connection alive"
        async for event in events:
            if self._closed: break
            yield event
