import asyncio
import json
import time
import uuid
from collections.abc import Callable
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any


@dataclass
class Event:
    type: str
    payload: dict[str, Any]
    event_id: str = ""
    timestamp: float = 0.0

    def __post_init__(self):
        if not self.event_id:
            self.event_id = str(uuid.uuid4())
        if not self.timestamp:
            self.timestamp = time.time()

    def to_dict(self) -> dict[str, Any]:
        return asdict(self)


class EventBus:
    def __init__(self, storage_path: str = "data-lab/events/events.jsonl"):
        self.storage_path = Path(storage_path)
        self.storage_path.parent.mkdir(parents=True, exist_ok=True)
        self._subscribers: list[Callable[[Event], None]] = []
        self._queues: list[asyncio.Queue] = []

    def subscribe(self, callback: Callable[[Event], None]):
        self._subscribers.append(callback)

    def register_queue(self) -> asyncio.Queue:
        q: asyncio.Queue = asyncio.Queue()
        self._queues.append(q)
        return q

    def unregister_queue(self, q: asyncio.Queue):
        if q in self._queues:
            self._queues.remove(q)

    def publish(self, event_type: str, payload: dict[str, Any]) -> Event:
        event = Event(type=event_type, payload=payload)
        data = event.to_dict()

        try:
            with open(self.storage_path, "a", encoding="utf-8") as f:
                f.write(json.dumps(data, ensure_ascii=False) + "\n")
        except Exception as e:
            print(f"[EventBus] Chyba zápisu události: {e}")

        for cb in self._subscribers:
            try:
                cb(event)
            except Exception as e:
                print(f"[EventBus] Chyba callbacku: {e}")

        for q in self._queues:
            try:
                q.put_nowait(data)
            except Exception as e:
                print(f"[EventBus] Chyba fronty: {e}")

        return event

    def get_recent(self, limit: int = 50) -> list[dict[str, Any]]:
        if not self.storage_path.exists():
            return []
        events = []
        try:
            with open(self.storage_path, encoding="utf-8") as f:
                lines = f.readlines()
            for line in lines[-limit:]:
                line = line.strip()
                if line:
                    events.append(json.loads(line))
        except Exception as e:
            print(f"[EventBus] Chyba při čtení: {e}")
        return events
