"""
Prometheus metric definitions for asgi-runway.

Supports both single-process and multi-process (gunicorn + uvicorn workers) modes.
Set PROMETHEUS_MULTIPROC_DIR env var to enable multi-process aggregation.

Environment variables
---------------------
APP_NAME
    Identifier added as a label to every metric. Used to distinguish services
    when all metrics are scraped into a single Prometheus server.
    Default: "unknown".
RUNWAY_MAX_CONNECTIONS
    When set, exposes a ``runway_max_connections`` gauge with this value so
    you can compute a capacity ratio in your Prometheus/KEDA query:
        sum(runway_requests_in_flight) / runway_max_connections
    Default: unset (feature disabled).
"""

import os

from prometheus_client import (
    GC_COLLECTOR,
    PLATFORM_COLLECTOR,
    PROCESS_COLLECTOR,
    REGISTRY,
    CollectorRegistry,
    Counter,
    Gauge,
    Histogram,
)

# ---------------------------------------------------------------------------
# Configuration from environment
# ---------------------------------------------------------------------------

APP_NAME: str = os.getenv("APP_NAME", "unknown")
_MAX_CONNECTIONS: int = int(os.getenv("RUNWAY_MAX_CONNECTIONS", "0"))

# ---------------------------------------------------------------------------
# Registry — multiprocess-aware
# ---------------------------------------------------------------------------

# prometheus_client requires PROMETHEUS_MULTIPROC_DIR to be set *before*
# metrics are created when running in multiprocess mode.
_MULTIPROCESS = "PROMETHEUS_MULTIPROC_DIR" in os.environ

if _MULTIPROCESS:
    from prometheus_client import multiprocess

    _registry = CollectorRegistry()
    multiprocess.MultiProcessCollector(_registry)
else:
    _registry = REGISTRY


def _make_registry() -> CollectorRegistry:
    """Return the active registry (multiprocess-aware)."""
    return _registry


def disable_runtime_metrics() -> None:
    """
    Unregister the default Python runtime collectors.

    Removes ``python_gc_*``, ``python_info``, and ``process_*`` metrics that
    prometheus_client registers automatically. Call this (or pass
    ``include_runtime_metrics=False`` to ``setup()``) when you only want
    runway metrics in your scrape output.

    Safe to call multiple times — silently ignores already-unregistered
    collectors.
    """
    for collector in (GC_COLLECTOR, PLATFORM_COLLECTOR, PROCESS_COLLECTOR):
        try:
            REGISTRY.unregister(collector)
        except Exception:
            pass


# ---------------------------------------------------------------------------
# Core autoscaling metric
# ---------------------------------------------------------------------------

_requests_in_flight = Gauge(
    "runway_requests_in_flight",
    "Number of HTTP requests currently being processed. "
    "Primary signal for pod autoscaling.",
    ["app_name"],
    multiprocess_mode="livesum",
)
# Pre-labeled so callers can do REQUESTS_IN_FLIGHT.inc() without passing app_name.
REQUESTS_IN_FLIGHT = _requests_in_flight.labels(app_name=APP_NAME)

# ---------------------------------------------------------------------------
# Observability metrics
# ---------------------------------------------------------------------------

REQUESTS_TOTAL = Counter(
    "runway_requests_total",
    "Total HTTP requests processed.",
    ["app_name", "method", "status"],
)

REQUEST_DURATION_SECONDS = Histogram(
    "runway_request_duration_seconds",
    "HTTP request duration in seconds.",
    ["app_name", "method"],
    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
)

# Optional per-route breakdown (populated only when route_groups is configured).
REQUESTS_IN_FLIGHT_BY_ROUTE = Gauge(
    "runway_requests_in_flight_by_route",
    "Requests currently being processed, broken down by route group.",
    ["app_name", "route"],
    multiprocess_mode="livesum",
)

# ---------------------------------------------------------------------------
# Capacity metric (only when RUNWAY_MAX_CONNECTIONS is set)
# ---------------------------------------------------------------------------

if _MAX_CONNECTIONS > 0:
    _max_conn_gauge = Gauge(
        "runway_max_connections",
        "Configured maximum concurrent connections (RUNWAY_MAX_CONNECTIONS). "
        "Use with runway_requests_in_flight to compute a capacity ratio:\n"
        "  sum(runway_requests_in_flight) / runway_max_connections",
        ["app_name"],
    )
    _max_conn_gauge.labels(app_name=APP_NAME).set(_MAX_CONNECTIONS)
