"""Swarm event log — records system events to SQLite.

Provides EventType enum, EventLogEntry dataclass, and log_event() function
used by error_capture, thinking engine, and the event broadcaster.

Events are persisted to SQLite and also published to the unified EventBus
(infrastructure.events.bus) for subscriber notification.
"""

import json
import logging
import sqlite3
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)

DB_PATH = Path("data/events.db")


class EventType(Enum):
    """All recognised event types in the system."""

    # Task lifecycle
    TASK_CREATED = "task.created"
    TASK_BIDDING = "task.bidding"
    TASK_ASSIGNED = "task.assigned"
    TASK_STARTED = "task.started"
    TASK_COMPLETED = "task.completed"
    TASK_FAILED = "task.failed"

    # Agent lifecycle
    AGENT_JOINED = "agent.joined"
    AGENT_LEFT = "agent.left"
    AGENT_STATUS_CHANGED = "agent.status_changed"

    # Bids
    BID_SUBMITTED = "bid.submitted"
    AUCTION_CLOSED = "auction.closed"

    # Tools
    TOOL_CALLED = "tool.called"
    TOOL_COMPLETED = "tool.completed"
    TOOL_FAILED = "tool.failed"

    # System
    SYSTEM_ERROR = "system.error"
    SYSTEM_WARNING = "system.warning"
    SYSTEM_INFO = "system.info"

    # Error capture
    ERROR_CAPTURED = "error.captured"
    BUG_REPORT_CREATED = "bug_report.created"

    # Thinking
    TIMMY_THOUGHT = "timmy.thought"


@dataclass
class EventLogEntry:
    """Single event in the log, used by the broadcaster for display."""

    id: str
    event_type: EventType
    source: str
    timestamp: str
    data: dict = field(default_factory=dict)
    task_id: str = ""
    agent_id: str = ""


def _ensure_db() -> sqlite3.Connection:
    DB_PATH.parent.mkdir(parents=True, exist_ok=True)
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA busy_timeout=5000")
    conn.execute("""
        CREATE TABLE IF NOT EXISTS events (
            id TEXT PRIMARY KEY,
            event_type TEXT NOT NULL,
            source TEXT DEFAULT '',
            task_id TEXT DEFAULT '',
            agent_id TEXT DEFAULT '',
            data TEXT DEFAULT '{}',
            timestamp TEXT NOT NULL
        )
    """)
    conn.commit()
    return conn


def _publish_to_event_bus(entry: EventLogEntry) -> None:
    """Publish an event to the unified EventBus (non-blocking).

    This bridges the synchronous log_event() callers to the async EventBus
    so subscribers get notified of all events regardless of origin.
    """
    try:
        import asyncio

        from infrastructure.events.bus import Event, event_bus

        event = Event(
            id=entry.id,
            type=entry.event_type.value,
            source=entry.source,
            data={
                **entry.data,
                "task_id": entry.task_id,
                "agent_id": entry.agent_id,
            },
            timestamp=entry.timestamp,
        )

        try:
            asyncio.get_running_loop()
            asyncio.create_task(event_bus.publish(event))
        except RuntimeError:
            # No event loop running — skip async publish
            pass
    except Exception:
        # Graceful degradation — never crash on EventBus integration
        pass


def log_event(
    event_type: EventType,
    source: str = "",
    data: Optional[dict] = None,
    task_id: str = "",
    agent_id: str = "",
) -> EventLogEntry:
    """Record an event and return the entry.

    Persists to SQLite, publishes to EventBus for subscribers,
    and broadcasts to WebSocket clients.
    """
    entry = EventLogEntry(
        id=str(uuid.uuid4()),
        event_type=event_type,
        source=source,
        timestamp=datetime.now(timezone.utc).isoformat(),
        data=data or {},
        task_id=task_id,
        agent_id=agent_id,
    )

    # Persist to SQLite
    try:
        db = _ensure_db()
        try:
            db.execute(
                "INSERT INTO events (id, event_type, source, task_id, agent_id, data, timestamp) "
                "VALUES (?, ?, ?, ?, ?, ?, ?)",
                (
                    entry.id,
                    event_type.value,
                    source,
                    task_id,
                    agent_id,
                    json.dumps(data or {}),
                    entry.timestamp,
                ),
            )
            db.commit()
        finally:
            db.close()
    except Exception as exc:
        logger.debug("Failed to persist event: %s", exc)

    # Publish to unified EventBus (non-blocking)
    _publish_to_event_bus(entry)

    # Broadcast to WebSocket clients (non-blocking)
    try:
        from infrastructure.events.broadcaster import event_broadcaster

        event_broadcaster.broadcast_sync(entry)
    except Exception:
        pass

    return entry


def get_task_events(task_id: str, limit: int = 50) -> list[EventLogEntry]:
    """Retrieve events for a specific task."""
    db = _ensure_db()
    try:
        rows = db.execute(
            "SELECT * FROM events WHERE task_id=? ORDER BY timestamp DESC LIMIT ?",
            (task_id, limit),
        ).fetchall()
    finally:
        db.close()

    entries = []
    for r in rows:
        try:
            et = EventType(r["event_type"])
        except ValueError:
            et = EventType.SYSTEM_INFO
        entries.append(
            EventLogEntry(
                id=r["id"],
                event_type=et,
                source=r["source"],
                timestamp=r["timestamp"],
                data=json.loads(r["data"]) if r["data"] else {},
                task_id=r["task_id"],
                agent_id=r["agent_id"],
            )
        )
    return entries
