"""CLI telemetry module for OpenTelemetry instrumentation.

This module provides end-to-end trace propagation from CLI to Nucleus to Agent.
Traces are exported to OTLP endpoint if configured, otherwise disabled.

Environment variables:
- TU_TELEMETRY_DISABLED: Set to "1" or "true" to disable CLI telemetry
- OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector endpoint (e.g., "http://localhost:4317")
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: OTLP traces endpoint (takes precedence)

Usage:
    from terminaluse.lib.cli.telemetry import init_cli_telemetry, cli_command_span

    # Initialize once at CLI startup
    init_cli_telemetry()

    # Wrap commands with spans
    with cli_command_span("tasks.create") as span:
        span.set_attribute("task.name", task_name)
        # ... command logic
"""

from __future__ import annotations

import os
from contextlib import contextmanager
from typing import TYPE_CHECKING, Iterator, Optional

if TYPE_CHECKING:
    from opentelemetry.trace import Span, Tracer

# Module-level state
_tracer: Optional["Tracer"] = None
_initialized = False


def _is_telemetry_enabled() -> bool:
    """Check if CLI telemetry is enabled."""
    disabled = os.environ.get("TU_TELEMETRY_DISABLED", "").lower()
    return disabled not in ("1", "true", "yes")


def _get_otlp_endpoint() -> Optional[str]:
    """Get the OTLP endpoint from environment."""
    # Traces-specific endpoint takes precedence
    endpoint = os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT")
    if endpoint:
        return endpoint
    # Fall back to generic endpoint
    return os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")


def init_cli_telemetry(
    service_name: str = "tu-cli",
    service_version: Optional[str] = None,
) -> bool:
    """Initialize OpenTelemetry for CLI.

    This sets up a TracerProvider with OTLP export if an endpoint is configured.
    If no OTLP endpoint is set, telemetry is silently disabled (no-op).

    Args:
        service_name: The service name for traces (default: "tu-cli")
        service_version: The service version (default: reads from terminaluse.version)

    Returns:
        True if telemetry was initialized, False if disabled or unavailable
    """
    global _tracer, _initialized

    if _initialized:
        return _tracer is not None

    if not _is_telemetry_enabled():
        _initialized = True
        return False

    otlp_endpoint = _get_otlp_endpoint()
    if not otlp_endpoint:
        # No endpoint configured - silently disable telemetry
        _initialized = True
        return False

    try:
        from opentelemetry import trace
        from opentelemetry.sdk.resources import SERVICE_NAME, SERVICE_VERSION, Resource
        from opentelemetry.sdk.trace import TracerProvider
        from opentelemetry.sdk.trace.export import BatchSpanProcessor

        # Get version if not provided
        if service_version is None:
            try:
                from terminaluse.version import __version__

                service_version = __version__
            except ImportError:
                service_version = "unknown"

        # Create resource with service info
        resource = Resource.create(
            {
                SERVICE_NAME: service_name,
                SERVICE_VERSION: service_version,
                "telemetry.sdk.name": "terminaluse-cli",
                "telemetry.sdk.language": "python",
            }
        )

        # Create tracer provider
        provider = TracerProvider(resource=resource)

        # Configure OTLP exporter
        try:
            from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

            # Check if endpoint uses gRPC (default) or HTTP
            if "4318" in otlp_endpoint or "/v1/traces" in otlp_endpoint:
                # HTTP endpoint
                from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
                    OTLPSpanExporter as HTTPOTLPSpanExporter,
                )

                exporter = HTTPOTLPSpanExporter(endpoint=otlp_endpoint)
            else:
                # gRPC endpoint (default)
                exporter = OTLPSpanExporter(
                    endpoint=otlp_endpoint,
                    insecure=not otlp_endpoint.startswith("https://"),
                )

            provider.add_span_processor(BatchSpanProcessor(exporter))

        except ImportError:
            # OTLP exporter not installed - telemetry disabled
            _initialized = True
            return False

        # Set as global provider
        trace.set_tracer_provider(provider)

        # Get tracer
        _tracer = trace.get_tracer("terminaluse.cli", service_version)

        _initialized = True
        return True

    except Exception:
        # Silently fail - telemetry should never break CLI
        _initialized = True
        return False


def get_tracer() -> "Tracer":
    """Get the CLI tracer instance.

    Returns a no-op tracer if telemetry is not initialized.
    """
    from opentelemetry import trace

    if not _initialized:
        init_cli_telemetry()

    return _tracer or trace.get_tracer("terminaluse.cli")


@contextmanager
def cli_command_span(
    command: str,
    print_trace_id: bool = False,
) -> Iterator["Span"]:
    """Context manager for CLI command spans.

    Creates a span for a CLI command with proper attributes and error handling.

    Args:
        command: The command name (e.g., "tasks.create", "deploy")
        print_trace_id: If True, prints the trace ID for debugging

    Yields:
        The active span for the command

    Example:
        with cli_command_span("tasks.create") as span:
            span.set_attribute("task.name", "my-task")
            # ... command logic
    """
    from opentelemetry import trace

    tracer = get_tracer()

    with tracer.start_as_current_span(
        f"cli.{command}",
        kind=trace.SpanKind.CLIENT,
        attributes={
            "cli.command": command,
            "cli.tool": "tu",
        },
    ) as span:
        if print_trace_id and span.is_recording():
            trace_id = format(span.get_span_context().trace_id, "032x")
            print(f"Trace ID: {trace_id}")

        try:
            yield span
        except Exception as e:
            span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
            span.record_exception(e)
            raise


def inject_trace_context(headers: dict) -> dict:
    """Inject W3C trace context into HTTP headers.

    Adds traceparent and tracestate headers for distributed tracing.

    Args:
        headers: Existing headers dict (will be modified in place)

    Returns:
        The headers dict with trace context injected
    """
    try:
        from opentelemetry.propagate import inject

        inject(headers)
    except Exception:
        # Silently fail - don't break requests if propagation fails
        pass
    return headers


def get_trace_headers() -> dict:
    """Get trace context headers for the current span.

    Returns:
        Dict with traceparent/tracestate headers, or empty dict if no active span
    """
    headers: dict = {}
    inject_trace_context(headers)
    return headers
