"""
CyberBrain26 LAB — Fáze 3F + 3G integrace do webapp.py
=======================================================

Tento modul NEMODIFIKUJE stávající webapp.py. Pouze se zaregistruje
přes `register(app)` a přidá:

- 3F-2: publikování systémových událostí (startup, enqueue)
- 3F-3: SSE endpointy /v1/events/recent a /v1/events/stream
- 3G:   task queue endpointy /v1/queue/status a /v1/queue/enqueue

Použití na konci webapp.py:

    from cyberbrain26.core.webapp_phase3fg import register as register_phase3fg
    register_phase3fg(app)
"""
from __future__ import annotations

import asyncio
import json
from typing import Any

from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse

from cyberbrain26.core.event_bus import EventBus
from cyberbrain26.core.task_queue import TaskQueue


def register(app: FastAPI) -> None:
    # Singleton instance — drží se na app.state, aby k nim měly přístup i jiné moduly
    bus = EventBus(storage_path="data-lab/events/events.jsonl")
    queue = TaskQueue(max_concurrent=3, event_bus=bus)

    app.state.event_bus = bus
    app.state.task_queue = queue

    # ------------------------------------------------------------------
    # 3F-2: Startup — nastartovat workery a publikovat systémovou událost
    # ------------------------------------------------------------------
    @app.on_event("startup")
    async def _phase3fg_startup() -> None:
        queue.start(3)
        bus.publish(
            "system.started",
            {"service": "webapp-lab", "port": 8180, "phase": "3F"},
        )

    # ------------------------------------------------------------------
    # 3G: Task Queue endpointy
    # ------------------------------------------------------------------
    @app.get("/v1/queue/status", tags=["queue"])
    async def queue_status() -> dict[str, Any]:
        return {"status": "ok", "queue": queue.get_status()}

    @app.post("/v1/queue/enqueue", tags=["queue"])
    async def queue_enqueue(request: Request) -> dict[str, Any]:
        data = await request.json()
        task_id = data.get("task_id") or f"task_{asyncio.get_event_loop().time():.0f}"
        payload = data.get("payload", {})
        await queue.enqueue(task_id, payload)
        bus.publish("task.enqueued", {"task_id": task_id, "payload_keys": list(payload.keys())})
        return {"status": "ok", "task_id": task_id, "message": "Task vlozen do fronty"}

    # ------------------------------------------------------------------
    # 3F-3: SSE streaming + historie událostí
    # ------------------------------------------------------------------
    @app.get("/v1/events/recent", tags=["events"])
    async def events_recent(limit: int = 50) -> dict[str, Any]:
        return {"status": "ok", "events": bus.get_recent(limit)}

    @app.get("/v1/events/stream", tags=["events"])
    async def events_stream() -> StreamingResponse:
        subscriber_queue: asyncio.Queue = bus.register_queue()

        async def event_generator():
            try:
                # Úvodní komentář — klient pozná, že spojení žije
                yield ": connected\n\n"
                while True:
                    try:
                        event = await asyncio.wait_for(subscriber_queue.get(), timeout=15.0)
                        yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
                    except TimeoutError:
                        # keep-alive ping každých 15 s, aby proxy nezavřela spojení
                        yield ": ping\n\n"
            finally:
                bus.unregister_queue(subscriber_queue)

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

    # ------------------------------------------------------------------
    # 3F-2 helper: publikování událostí z jiných endpointů
    # ------------------------------------------------------------------
    def publish_event(event_type: str, payload: dict | None = None) -> None:
        """Pomocná funkce pro publish z jakéhokoli endpointu."""
        bus.publish(event_type, payload or {})

    app.state.publish_event = publish_event
