"""
Unified OpenTelemetry Telemetry Setup

Provides a single entry point to configure all telemetry signals:
- Traces: Distributed tracing across services
- Metrics: OTLP metrics export + system metrics collection
- Logs: Structured logs with trace correlation

All signals are exported to SigNoz via OTLP.
"""

import os
import structlog
from typing import Optional, Dict, Any, Tuple
from dataclasses import dataclass

from .otel_config import OTelConfig
from .tracing import setup_tracing
from .metrics_exporter import setup_otel_metrics
from .logs_exporter import setup_otel_logging
from .system_metrics import setup_all_metrics, SystemMetricsCollector, ApplicationMetricsCollector

logger = structlog.get_logger()


@dataclass
class TelemetryProviders:
    """
    Container for all OpenTelemetry providers and collectors.

    Attributes:
        tracer_provider: Provider for distributed tracing
        meter_provider: Provider for metrics export
        logging_handler: Handler for structured logs
        system_metrics: Collector for system-level metrics (CPU, memory, disk, network)
        app_metrics: Collector for application-level metrics (HTTP, DB)
    """
    tracer_provider: Optional[Any] = None
    meter_provider: Optional[Any] = None
    logging_handler: Optional[Any] = None
    system_metrics: Optional[SystemMetricsCollector] = None
    app_metrics: Optional[ApplicationMetricsCollector] = None


def setup_telemetry(
    app,
    service_name: str,
    service_version: str = "1.0.0",
    enable_traces: bool = True,
    enable_metrics: bool = True,
    enable_logs: bool = True,
    enable_system_metrics: bool = True,
    metrics_protocol: Optional[str] = None,  # "grpc" or "http", defaults to grpc
    export_interval_millis: int = 60000
) -> TelemetryProviders:
    """
    Setup all OpenTelemetry telemetry signals (traces, metrics, logs) for a service.

    This is the UNIFIED setup function that configures everything:
    - Distributed tracing (gRPC, port 4317)
    - Metrics export (gRPC by default, port 4317)
    - System metrics collection (CPU, memory, disk, network)
    - Application metrics (HTTP requests, DB queries)
    - Structured logs export (HTTP, port 4318)

    All signals use the centralized OTelConfig for endpoint management.

    Args:
        app: FastAPI application instance
        service_name: Name of the service (e.g., "auth-service")
        service_version: Version of the service
        enable_traces: Enable distributed tracing (default: True)
        enable_metrics: Enable metrics export to OTLP (default: True)
        enable_logs: Enable logs export to OTLP (default: True)
        enable_system_metrics: Enable system metrics collection (default: True, can be disabled via ENABLE_SYSTEM_METRICS env)
        metrics_protocol: Protocol for metrics ("grpc" or "http", default: "grpc")
        export_interval_millis: How often to export metrics in milliseconds

    Returns:
        TelemetryProviders containing all initialized providers and collectors

    Example:
        from shared.monitoring.telemetry import setup_telemetry

        app = FastAPI(title="Auth Service")
        providers = setup_telemetry(
            app,
            service_name="auth-service",
            service_version="1.0.0"
        )

        # All telemetry is now configured:
        # - Traces automatically captured for HTTP requests
        # - System metrics automatically collected
        # - Application metrics via providers.app_metrics
        # - Logs automatically correlated with traces
    """

    logger.info(
        "Setting up unified OpenTelemetry telemetry",
        service=service_name,
        version=service_version,
        traces=enable_traces,
        metrics=enable_metrics,
        logs=enable_logs,
        system_metrics=enable_system_metrics
    )

    providers = TelemetryProviders()

    # Setup distributed tracing
    if enable_traces and OTelConfig.is_enabled("traces"):
        try:
            providers.tracer_provider = setup_tracing(
                app,
                service_name=service_name,
                service_version=service_version
            )
            if providers.tracer_provider:
                logger.info("✓ Distributed tracing configured", service=service_name)
            else:
                logger.warning("✗ Distributed tracing setup returned None", service=service_name)
        except Exception as e:
            logger.error("✗ Failed to setup distributed tracing", service=service_name, error=str(e))

    # Setup OTLP metrics export
    if enable_metrics and OTelConfig.is_enabled("metrics"):
        try:
            providers.meter_provider = setup_otel_metrics(
                service_name=service_name,
                service_version=service_version,
                protocol=metrics_protocol,
                export_interval_millis=export_interval_millis
            )
            if providers.meter_provider:
                logger.info("✓ OTLP metrics export configured", service=service_name)

                # Setup system and application metrics collectors
                if enable_system_metrics:
                    enable_system_env = os.getenv("ENABLE_SYSTEM_METRICS", "true").lower() == "true"
                    if enable_system_env:
                        try:
                            providers.system_metrics, providers.app_metrics = setup_all_metrics(
                                service_name=service_name,
                                service_version=service_version,
                                meter_provider=providers.meter_provider
                            )
                            logger.info(
                                "✓ System and application metrics collectors initialized",
                                service=service_name,
                                system_metrics=["cpu", "memory", "disk", "network"],
                                app_metrics=["http_requests", "db_queries"]
                            )
                        except Exception as e:
                            logger.warning("✗ Failed to setup metrics collectors", service=service_name, error=str(e))
            else:
                logger.warning("✗ OTLP metrics export setup returned None", service=service_name)
        except Exception as e:
            logger.error("✗ Failed to setup OTLP metrics export", service=service_name, error=str(e))

    # Setup logs export
    if enable_logs and OTelConfig.is_enabled("logs"):
        try:
            providers.logging_handler = setup_otel_logging(
                service_name=service_name,
                service_version=service_version
            )
            if providers.logging_handler:
                logger.info("✓ Structured logs export configured", service=service_name)
            else:
                logger.warning("✗ Logs export setup returned None", service=service_name)
        except Exception as e:
            logger.error("✗ Failed to setup logs export", service=service_name, error=str(e))

    # Log endpoint configuration summary
    try:
        endpoints = OTelConfig.get_endpoints()
        summary = {
            "service": service_name,
            "version": service_version,
            "traces": {
                "enabled": bool(providers.tracer_provider),
                "endpoint": endpoints.traces_grpc if providers.tracer_provider else "disabled"
            },
            "metrics": {
                "enabled": bool(providers.meter_provider),
                "endpoint": (endpoints.metrics_grpc if metrics_protocol != "http" else endpoints.metrics_http) if providers.meter_provider else "disabled",
                "system_metrics": bool(providers.system_metrics),
                "app_metrics": bool(providers.app_metrics)
            },
            "logs": {
                "enabled": bool(providers.logging_handler),
                "endpoint": endpoints.logs_http if providers.logging_handler else "disabled"
            }
        }
        logger.info("🎉 Telemetry setup complete", **summary)
    except Exception as e:
        logger.warning("Could not log endpoint summary", error=str(e))

    return providers


def setup_telemetry_simple(
    app,
    service_name: str,
    service_version: str = "1.0.0"
) -> TelemetryProviders:
    """
    Simplified telemetry setup with all defaults.

    Uses:
    - gRPC for traces (port 4317)
    - gRPC for metrics (port 4317)
    - HTTP for logs (port 4318)

    All settings are read from environment variables and OTelConfig.

    Args:
        app: FastAPI application instance
        service_name: Name of the service
        service_version: Version of the service

    Returns:
        TelemetryProviders containing all initialized providers

    Example:
        from shared.monitoring.telemetry import setup_telemetry_simple

        app = FastAPI(title="Auth Service")
        providers = setup_telemetry_simple(app, "auth-service")
    """
    return setup_telemetry(
        app=app,
        service_name=service_name,
        service_version=service_version
    )


def get_telemetry_status() -> Dict[str, Any]:
    """
    Get current telemetry configuration status.

    Returns:
        Dictionary with telemetry status information

    Example:
        from shared.monitoring.telemetry import get_telemetry_status

        status = get_telemetry_status()
        print(f"Tracing enabled: {status['traces']['enabled']}")
    """
    endpoints = OTelConfig.get_endpoints()

    return {
        "traces": {
            "enabled": OTelConfig.is_enabled("traces"),
            "protocol": "grpc",
            "endpoint": endpoints.traces_grpc
        },
        "metrics": {
            "enabled": OTelConfig.is_enabled("metrics"),
            "protocol": OTelConfig.get_protocol("metrics"),
            "grpc_endpoint": endpoints.metrics_grpc,
            "http_endpoint": endpoints.metrics_http
        },
        "logs": {
            "enabled": OTelConfig.is_enabled("logs"),
            "protocol": "http",
            "endpoint": endpoints.logs_http
        }
    }
