"""
Telemetry — Structured reasoning trace logging.

Every decision NeuralClaw makes is logged with full provenance using
the reasoning trace format from the blueprint:

    [2026-02-22 14:30:15] PERCEPTION: Message from Telegram, intent=command, threat=0.02
"""

from __future__ import annotations

import logging
import sys
from datetime import datetime, timezone
from pathlib import Path

from rich.console import Console
from rich.text import Text

from neuralclaw.bus.neural_bus import Event, EventType
from neuralclaw.config import LOG_DIR

# ---------------------------------------------------------------------------
# Cortex label mapping
# ---------------------------------------------------------------------------

_CORTEX_MAP: dict[EventType, str] = {
    EventType.SIGNAL_RECEIVED: "PERCEPTION",
    EventType.THREAT_SCREENED: "SECURITY",
    EventType.INTENT_CLASSIFIED: "PERCEPTION",
    EventType.CONTEXT_ENRICHED: "PERCEPTION",
    EventType.MEMORY_QUERY: "MEMORY",
    EventType.MEMORY_RETRIEVED: "MEMORY",
    EventType.MEMORY_STORED: "MEMORY",
    EventType.REASONING_STARTED: "REASONING",
    EventType.REASONING_FAST_PATH: "REASONING",
    EventType.REASONING_DELIBERATE: "REASONING",
    EventType.REASONING_COMPLETE: "REASONING",
    EventType.ACTION_REQUESTED: "ACTION",
    EventType.ACTION_EXECUTING: "ACTION",
    EventType.ACTION_COMPLETE: "ACTION",
    EventType.ACTION_DENIED: "ACTION",
    EventType.RESPONSE_READY: "RESPONSE",
    EventType.RESPONSE_SENT: "RESPONSE",
    EventType.ERROR: "ERROR",
    EventType.SHUTDOWN: "SYSTEM",
}

_CORTEX_COLORS: dict[str, str] = {
    "PERCEPTION": "cyan",
    "SECURITY": "red",
    "MEMORY": "magenta",
    "REASONING": "yellow",
    "ACTION": "green",
    "RESPONSE": "blue",
    "ERROR": "bold red",
    "SYSTEM": "dim white",
    "CONFIDENCE": "bright_yellow",
}


# ---------------------------------------------------------------------------
# Telemetry logger
# ---------------------------------------------------------------------------

class Telemetry:
    """
    Structured reasoning trace logger.

    Subscribes to ALL events on the neural bus and outputs formatted
    reasoning traces to both file and (optionally) stdout via Rich.
    """

    def __init__(
        self,
        log_to_file: bool = True,
        log_to_stdout: bool = True,
        log_dir: Path | None = None,
    ) -> None:
        self._console = Console(stderr=True) if log_to_stdout else None
        self._log_to_stdout = log_to_stdout

        # File logger
        self._file_logger: logging.Logger | None = None
        if log_to_file:
            log_path = (log_dir or LOG_DIR)
            log_path.mkdir(parents=True, exist_ok=True)
            log_file = log_path / "reasoning_traces.log"

            self._file_logger = logging.getLogger("neuralclaw.telemetry")
            self._file_logger.setLevel(logging.DEBUG)
            handler = logging.FileHandler(log_file, encoding="utf-8")
            handler.setFormatter(logging.Formatter("%(message)s"))
            self._file_logger.addHandler(handler)
            self._file_logger.propagate = False

    def handle_event(self, event: Event) -> None:
        """Event handler — subscribe this to the neural bus with subscribe_all()."""
        cortex = _CORTEX_MAP.get(event.type, "SYSTEM")
        ts = datetime.fromtimestamp(event.timestamp, tz=timezone.utc).strftime(
            "%Y-%m-%d %H:%M:%S"
        )

        # Build detail string from event data
        details = self._format_details(event)
        line = f"[{ts}] {cortex}: {details}"

        # File output
        if self._file_logger:
            self._file_logger.info(line)

        # Rich stdout output
        if self._console and self._log_to_stdout:
            color = _CORTEX_COLORS.get(cortex, "white")
            ts_text = Text(f"[{ts}] ", style="dim")
            cortex_text = Text(f"{cortex}: ", style=f"bold {color}")
            detail_text = Text(details, style=color)
            self._console.print(ts_text + cortex_text + detail_text, highlight=False)

    def _format_details(self, event: Event) -> str:
        """Format event data into a human-readable detail string."""
        data = event.data
        etype = event.type

        if etype == EventType.SIGNAL_RECEIVED:
            src = data.get("source", "unknown")
            preview = data.get("content", "")[:60]
            return f"Message from {src}: \"{preview}\""

        if etype == EventType.THREAT_SCREENED:
            score = data.get("score", 0)
            blocked = data.get("blocked", False)
            status = "BLOCKED" if blocked else "passed"
            return f"threat={score:.2f}, status={status}"

        if etype == EventType.INTENT_CLASSIFIED:
            intent = data.get("intent", "unknown")
            conf = data.get("confidence", 0)
            return f"intent={intent}, confidence={conf:.2f}"

        if etype == EventType.MEMORY_RETRIEVED:
            ep = data.get("episodic_count", 0)
            sem = data.get("semantic_count", 0)
            return f"Retrieved {ep} episodic, {sem} semantic memories"

        if etype == EventType.REASONING_STARTED:
            path = data.get("path", "deliberative")
            return f"{path.capitalize()} path selected"

        if etype == EventType.REASONING_COMPLETE:
            conf = data.get("confidence", 0)
            source = data.get("source", "llm")
            return f"Confidence: {conf:.2f} | Source: {source}"

        if etype == EventType.ACTION_REQUESTED:
            skill = data.get("skill", "unknown")
            cap = data.get("capability", "")
            return f"{skill} invoked (capability: {cap})"

        if etype == EventType.ACTION_DENIED:
            skill = data.get("skill", "unknown")
            reason = data.get("reason", "")
            return f"{skill} DENIED — {reason}"

        if etype == EventType.RESPONSE_READY:
            preview = data.get("content", "")[:80]
            return f"\"{preview}\""

        if etype == EventType.ERROR:
            return f"ERROR: {data.get('error', 'unknown')}"

        # Default: dump data keys
        parts = [f"{k}={v}" for k, v in data.items()]
        return ", ".join(parts) if parts else event.type.name
