"""SSE endpoint for streaming domain events to the dashboard.

Subscribes to the global EventStore and pushes events to connected
clients via Server-Sent Events (text/event-stream).  The frontend
uses EventSource to receive real-time updates without polling.

Auth: token passed as query parameter (SSE doesn't support custom headers).
"""
from __future__ import annotations

import asyncio
import json
import time
from typing import Any

from fastapi import APIRouter, Query, Request
from starlette.responses import StreamingResponse

import structlog

logger = structlog.get_logger()

router = APIRouter(tags=["events"])


def _check_token(token: str | None) -> bool:
    """Verify the SSE auth token matches the configured API key."""
    if not token:
        return False
    try:
        from proxym.config import get_settings
        settings = get_settings()
        expected = settings.master_key or settings.default_api_key or "sk-proxy-local-dev"
        return token == expected
    except Exception:
        return token == "sk-proxy-local-dev"


@router.get("/events/stream")
async def events_stream(
    request: Request,
    token: str | None = Query(None),
):
    """SSE endpoint — streams domain events as JSON.

    Connect: GET /dashboard/events/stream?token=<api_key>
    Each message is a JSON object with event_type, aggregate_id, data, timestamp.
    """
    if not _check_token(token):
        return StreamingResponse(
            iter(["data: {\"error\": \"unauthorized\"}\n\n"]),
            status_code=401,
            media_type="text/event-stream",
        )

    async def event_generator():
        from proxym.domain.setup import get_event_store

        store = get_event_store()
        queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue(maxsize=256)

        def on_event(event):
            try:
                payload = event.to_dict()
                queue.put_nowait(payload)
            except asyncio.QueueFull:
                pass  # drop if client can't keep up

        store.subscribe(on_event)

        try:
            # Send initial keepalive
            yield f"data: {json.dumps({'event_type': 'connected', 'timestamp': time.time()})}\n\n"

            while True:
                if await request.is_disconnected():
                    break
                try:
                    payload = await asyncio.wait_for(queue.get(), timeout=30.0)
                    yield f"data: {json.dumps(payload, default=str)}\n\n"
                except asyncio.TimeoutError:
                    # Send keepalive every 30s to prevent proxy/browser timeout
                    yield f": keepalive {time.time()}\n\n"
        except asyncio.CancelledError:
            pass
        finally:
            # Unsubscribe (best effort)
            try:
                store._subscribers.remove(on_event)
            except ValueError:
                pass

    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no",
        },
    )
