"""Build state emitter -- tracks system state for dashboards.

Emits a JSON-serializable state snapshot that Mission Control
dashboards can consume. Stdlib-only.
"""

from __future__ import annotations

import json
import time
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path
from typing import Any


class BuildPhase(Enum):
    """Build lifecycle phases."""

    BOOTSTRAP = "bootstrap"
    BUILDING = "building"
    TESTING = "testing"
    DEPLOYING = "deploying"
    STABLE = "stable"


@dataclass
class ComponentStatus:
    """Status of a single tracked component."""

    name: str
    status: str = "pending"  # pending, building, ready, error
    version: str = ""
    test_count: int = 0
    coverage: float = 0.0
    last_updated: float = field(default_factory=time.time)

    def to_dict(self) -> dict[str, Any]:
        """Serialize to a JSON-compatible dict."""
        return {
            "name": self.name,
            "status": self.status,
            "version": self.version,
            "test_count": self.test_count,
            "coverage": self.coverage,
            "last_updated": self.last_updated,
        }


class StateEmitter:
    """Tracks and emits build/runtime state for Mission Control dashboards."""

    def __init__(self, version: str = "0.1.0") -> None:
        self._version = version
        self._start_time = time.time()
        self._phase = BuildPhase.STABLE
        self._components: dict[str, ComponentStatus] = {}
        self._events: list[dict[str, Any]] = []
        self._max_events = 100
        self._listeners: list[Any] = []

    def set_phase(self, phase: BuildPhase) -> None:
        """Transition to a new build phase."""
        self._phase = phase
        self._emit_event("phase_change", {"phase": phase.value})

    def update_component(self, name: str, **kwargs: Any) -> ComponentStatus:
        """Create or update a tracked component."""
        if name not in self._components:
            self._components[name] = ComponentStatus(name=name)
        comp = self._components[name]
        for k, v in kwargs.items():
            if hasattr(comp, k):
                object.__setattr__(comp, k, v)
        comp.last_updated = time.time()
        self._emit_event("component_update", {"component": name, **kwargs})
        return comp

    def add_listener(self, callback: Any) -> None:
        """Register a callback that receives every emitted event."""
        self._listeners.append(callback)

    def remove_listener(self, callback: Any) -> None:
        """Remove a previously registered listener."""
        self._listeners = [ln for ln in self._listeners if ln is not callback]

    def snapshot(self) -> dict[str, Any]:
        """Full state snapshot for Mission Control."""
        return {
            "version": self._version,
            "phase": self._phase.value,
            "uptime_seconds": round(time.time() - self._start_time, 1),
            "components": {name: comp.to_dict() for name, comp in sorted(self._components.items())},
            "recent_events": self._events[-20:],
            "timestamp": time.time(),
        }

    def snapshot_json(self) -> str:
        """Return snapshot as a JSON string."""
        return json.dumps(self.snapshot(), indent=2)

    def save_snapshot(self, path: str | Path) -> None:
        """Persist the current snapshot to disk."""
        p = Path(path)
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(self.snapshot_json())

    def _emit_event(self, event_type: str, data: dict[str, Any]) -> None:
        """Record an event and notify all listeners."""
        event: dict[str, Any] = {
            "type": event_type,
            "data": data,
            "timestamp": time.time(),
        }
        self._events.append(event)
        if len(self._events) > self._max_events:
            self._events = self._events[-self._max_events :]
        for listener in self._listeners:
            try:
                listener(event)
            except Exception:  # noqa: BLE001
                pass

    @property
    def events(self) -> list[dict[str, Any]]:
        """Return a copy of the event history."""
        return list(self._events)

    @property
    def phase(self) -> BuildPhase:
        """Current build phase."""
        return self._phase

    @property
    def components(self) -> dict[str, ComponentStatus]:
        """Return a copy of the component registry."""
        return dict(self._components)
