"""
Console exporter for local debugging.

Prints spans to stdout in a readable format.
"""

from __future__ import annotations

import json
import sys
from typing import Any, Dict, List, TextIO, TYPE_CHECKING

from risicare.exporters.base import ExportResult, SpanExporter

if TYPE_CHECKING:
    from risicare_core import Span


class ConsoleExporter(SpanExporter):
    """
    Exporter that prints spans to the console.

    Useful for local development and debugging.
    """

    def __init__(
        self,
        output: TextIO = sys.stdout,
        pretty: bool = True,
        show_attributes: bool = True,
        show_events: bool = True,
    ):
        """
        Initialize the console exporter.

        Args:
            output: Output stream (default: stdout).
            pretty: Whether to pretty-print output.
            show_attributes: Whether to show span attributes.
            show_events: Whether to show span events.
        """
        self._output = output
        self._pretty = pretty
        self._show_attributes = show_attributes
        self._show_events = show_events

    def export(self, spans: List["Span"]) -> ExportResult:
        """Export spans to console."""
        try:
            for span in spans:
                self._print_span(span)
            return ExportResult.SUCCESS
        except Exception:
            return ExportResult.FAILURE

    def _print_span(self, span: "Span") -> None:
        """Print a single span."""
        if self._pretty:
            self._print_pretty(span)
        else:
            self._print_json(span)

    def _print_pretty(self, span: "Span") -> None:
        """Print span in human-readable format."""
        # Status indicator
        if span.is_error:
            status = "\033[31m[ERROR]\033[0m"  # Red
        elif span.status.value == "ok":
            status = "\033[32m[OK]\033[0m"     # Green
        else:
            status = "\033[33m[...]\033[0m"    # Yellow

        # Duration
        duration = f"{span.duration_ms:.2f}ms" if span.duration_ms else "ongoing"

        # Header line
        self._output.write(
            f"{status} {span.name} "
            f"({span.kind.value}) "
            f"[{duration}]\n"
        )

        # IDs
        self._output.write(
            f"  trace: {span.trace_id[:8]}... "
            f"span: {span.span_id[:8]}...\n"
        )

        # Agent/Session info
        if span.agent_id or span.session_id:
            parts = []
            if span.agent_id:
                parts.append(f"agent={span.agent_id}")
            if span.session_id:
                parts.append(f"session={span.session_id}")
            self._output.write(f"  {' '.join(parts)}\n")

        # Phase
        if span.semantic_phase:
            self._output.write(f"  phase: {span.semantic_phase.value}\n")

        # LLM info
        if span.llm:
            llm = span.llm
            llm_parts = []
            if llm.model:
                llm_parts.append(f"model={llm.model}")
            if llm.total_tokens:
                llm_parts.append(f"tokens={llm.total_tokens}")
            if llm.cost_usd:
                llm_parts.append(f"cost=${llm.cost_usd:.4f}")
            if llm_parts:
                self._output.write(f"  llm: {' '.join(llm_parts)}\n")

        # Attributes
        if self._show_attributes and span.attributes:
            self._output.write("  attributes:\n")
            for key, value in span.attributes.items():
                self._output.write(f"    {key}: {_truncate(value, 80)}\n")

        # Events
        if self._show_events and span.events:
            self._output.write(f"  events: {len(span.events)}\n")
            for event in span.events[:5]:  # Show first 5 events
                self._output.write(f"    - {event.name}\n")
            if len(span.events) > 5:
                self._output.write(f"    ... and {len(span.events) - 5} more\n")

        # Exceptions
        if span.exceptions:
            self._output.write("  exceptions:\n")
            for exc in span.exceptions:
                self._output.write(f"    - {exc.type}: {exc.message[:50]}...\n")

        self._output.write("\n")
        self._output.flush()

    def _print_json(self, span: "Span") -> None:
        """Print span as JSON."""
        data = span.to_dict()
        _truncate_content_fields(data)
        self._output.write(json.dumps(data) + "\n")
        self._output.flush()


def _truncate(value: Any, max_length: int) -> str:
    """Truncate a value to max length."""
    s = str(value)
    if len(s) > max_length:
        return s[:max_length - 3] + "..."
    return s


# Fields that may contain full prompt/completion content (PII risk)
_CONTENT_FIELDS = {"prompt", "completion", "input", "output", "content", "messages", "text"}
_CONTENT_MAX_LENGTH = 200


def _truncate_content_fields(data: Any, max_length: int = _CONTENT_MAX_LENGTH) -> None:
    """Truncate long content fields in-place to avoid logging PII in JSON mode."""
    if isinstance(data, dict):
        for key, value in data.items():
            if key in _CONTENT_FIELDS and isinstance(value, str) and len(value) > max_length:
                data[key] = value[:max_length] + "...[truncated]"
            else:
                _truncate_content_fields(value, max_length)
    elif isinstance(data, list):
        for item in data:
            _truncate_content_fields(item, max_length)
