"""SSE router — streams domain mutation events to authenticated clients.

GET /api/v1/sse/events keeps the connection open and yields JSON `data:` frames
for reservation/order/customer changes scoped to the caller's restaurant.
"""

from collections.abc import AsyncGenerator

import logfire
from fastapi import APIRouter, Depends, Request
from fastapi.responses import StreamingResponse

from app.auth.tenant import get_current_restaurant
from app.models.restaurant import Restaurant
from app.realtime.connection_manager import manager
from app.realtime.events import DomainEvent

router = APIRouter(prefix="/sse", tags=["sse"])


async def _event_stream(
    conn_id: str, restaurant_id: str, request: Request
) -> AsyncGenerator[str, None]:
    """Yield SSE frames from the connection's queue until disconnect."""
    conn = manager._connections.get(conn_id)
    if conn is None:
        return

    try:
        while True:
            # Check if client disconnected
            if await request.is_disconnected():
                break

            try:
                event: DomainEvent | None = await conn.queue.get()
            except Exception:
                break

            if event is None:  # sentinel — connection closed
                break

            yield f"data: {event.model_dump_json()}\n\n"
    finally:
        manager.disconnect(conn_id)
        logfire.info(
            "sse_stream_ended",
            connection_id=conn_id,
            restaurant_id=restaurant_id,
        )


@router.get("/events")
async def sse_events(
    request: Request,
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> StreamingResponse:
    """Authenticated SSE endpoint for restaurant-scoped domain events."""
    conn = manager.register(restaurant.id)

    logfire.info(
        "sse_stream_started",
        connection_id=conn.id,
        restaurant_id=restaurant.id,
    )

    from app.realtime import sse_response

    return sse_response(_event_stream(conn.id, restaurant.id, request))
