import logging
from typing import Optional

from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource

from .config import ObservabilityConfig

logger = logging.getLogger(__name__)

_meter_provider = None

# Lazy-initialized metric helpers
_request_counter = None
_request_duration = None
_active_connections = None


def setup_metrics(enable_system_metrics: bool = True) -> bool:
    global _meter_provider

    if not ObservabilityConfig.OTEL_ENABLED or not ObservabilityConfig.OTEL_EXPORTER_OTLP_ENDPOINT:
        return False

    try:
        resource = Resource.create({
            "service.name": ObservabilityConfig.OTEL_SERVICE_NAME,
            "service.version": ObservabilityConfig.OTEL_SERVICE_VERSION,
            "deployment.environment": ObservabilityConfig.OTEL_DEPLOYMENT_ENVIRONMENT,
        })

        headers = ObservabilityConfig.parse_headers()

        if ObservabilityConfig.OTEL_EXPORTER_OTLP_PROTOCOL == "grpc":
            from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
            endpoint = ObservabilityConfig.OTEL_EXPORTER_OTLP_ENDPOINT
            insecure = not ObservabilityConfig.is_secure_endpoint()
            exporter = OTLPMetricExporter(
                endpoint=endpoint,
                headers=headers if headers else None,
                insecure=insecure,
            )
        else:
            from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
            endpoint = ObservabilityConfig.OTEL_EXPORTER_OTLP_ENDPOINT
            if not endpoint.endswith("/v1/metrics"):
                endpoint = endpoint.rstrip("/") + "/v1/metrics"
            exporter = OTLPMetricExporter(
                endpoint=endpoint,
                headers=headers if headers else None,
            )

        export_interval = ObservabilityConfig.OTEL_METRIC_EXPORT_INTERVAL
        reader = PeriodicExportingMetricReader(exporter, export_interval_millis=export_interval)
        _meter_provider = MeterProvider(resource=resource, metric_readers=[reader])
        metrics.set_meter_provider(_meter_provider)

        if enable_system_metrics:
            _instrument_system_metrics()

        return True

    except Exception as e:
        logger.error(f"Failed to setup metrics: {e}", exc_info=True)
        return False


def _instrument_system_metrics(collect_per_cpu: bool = False) -> None:
    """Instrument system and runtime metrics (CPU, memory, disk, network, process)."""
    try:
        from .system_metrics import start_system_metrics

        meter = get_meter()
        start_system_metrics(meter, collect_per_cpu=collect_per_cpu)
        logger.info("System metrics instrumentation enabled (built-in psutil collector)")
    except ImportError:
        logger.warning(
            "psutil is not installed — system metrics disabled. "
            "Install with: pip install varicon-observability[metrics]"
        )
    except Exception as e:
        logger.warning(f"System metrics instrumentation failed: {e}", exc_info=True)


def get_meter(
    name: Optional[str] = None,
    version: Optional[str] = None,
):
    """
    Get a meter for creating custom metrics. Call setup_observability() first.

    Args:
        name: Meter name (default: service name from config)
        version: Meter version (default: service version from config)

    Returns:
        OpenTelemetry Meter instance for creating counters, histograms, gauges, etc.
    """
    return metrics.get_meter(
        name or ObservabilityConfig.OTEL_SERVICE_NAME,
        version or ObservabilityConfig.OTEL_SERVICE_VERSION,
    )


def get_request_counter():
    """Get a counter for tracking request counts. Creates on first call."""
    global _request_counter
    if _request_counter is None:
        meter = get_meter()
        _request_counter = meter.create_counter(
            name="http.server.request.count",
            unit="1",
            description="Total number of HTTP requests",
        )
    return _request_counter


def get_request_duration_histogram():
    """Get a histogram for tracking request duration. Creates on first call."""
    global _request_duration
    if _request_duration is None:
        meter = get_meter()
        _request_duration = meter.create_histogram(
            name="http.server.request.duration",
            unit="ms",
            description="HTTP request duration in milliseconds",
        )
    return _request_duration


def get_active_connections_counter():
    """Get an up-down counter for tracking active connections. Creates on first call."""
    global _active_connections
    if _active_connections is None:
        meter = get_meter()
        _active_connections = meter.create_up_down_counter(
            name="connections.active",
            unit="1",
            description="Number of active connections",
        )
    return _active_connections
