"""LLMHosts Prometheus metrics -- expose metrics in Prometheus format for monitoring.

Provides a ``/metrics`` endpoint that exposes:
- HTTP request counters (method, path, status)
- Request latency histograms
- Active backends gauge
- Cache hit rate gauge

This module is part of T-12 (World-Class Logging & Monitoring) compliance.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from prometheus_client import REGISTRY, Counter, Gauge, Histogram, make_asgi_app

if TYPE_CHECKING:
    from llmhosts.metrics.collector import MetricsCollector

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Prometheus metrics
# ---------------------------------------------------------------------------

# HTTP request counter
http_requests_total = Counter(
    "http_requests_total",
    "Total HTTP requests",
    labelnames=["method", "path", "status"],
)

# HTTP request latency histogram (buckets in seconds)
http_request_duration_seconds = Histogram(
    "http_request_duration_seconds",
    "HTTP request latency",
    labelnames=["method", "path"],
    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
)

# Active backends gauge
active_backends = Gauge(
    "active_backends",
    "Number of active backends",
)

# Cache hit rate gauge (0.0 to 1.0)
cache_hit_rate = Gauge(
    "cache_hit_rate",
    "Cache hit rate (rolling window)",
)

# LLM-specific metrics
llm_requests_total = Counter(
    "llm_requests_total",
    "Total LLM requests",
    labelnames=["backend", "model", "cached"],
)

llm_tokens_total = Counter(
    "llm_tokens_total",
    "Total tokens processed",
    labelnames=["backend", "model"],
)

llm_cost_usd_total = Counter(
    "llm_cost_usd_total",
    "Total cost in USD",
    labelnames=["backend"],
)

llm_savings_usd_total = Counter(
    "llm_savings_usd_total",
    "Total savings vs cloud in USD",
)

# Cache eviction counter (per tier)
cache_evictions_total = Counter(
    "llmhosts_cache_evictions_total",
    "Total cache entries evicted by LRU",
    labelnames=["tier"],
)


# ---------------------------------------------------------------------------
# Metrics exporter
# ---------------------------------------------------------------------------


class PrometheusMetricsExporter:
    """Synchronizes LLMHosts MetricsCollector state with Prometheus gauges."""

    def __init__(self, collector: MetricsCollector) -> None:
        """
        Parameters
        ----------
        collector:
            The LLMHosts MetricsCollector to export from.
        """
        self._collector = collector

    def update_gauges(self) -> None:
        """Update Prometheus gauges from the current MetricsCollector snapshot.

        This should be called periodically (e.g., every 15s) to refresh
        gauge values for Prometheus scraping.
        """
        snap = self._collector.snapshot()

        # Update cache hit rate
        cache_hit_rate.set(snap.cache_hit_rate)

        # Update active backends count
        active_backends.set(len(snap.requests_by_backend))

        # Note: Counters (http_requests_total, etc.) are incremented
        # directly in middleware, not synchronized from the collector.


# ---------------------------------------------------------------------------
# ASGI app factory
# ---------------------------------------------------------------------------


def create_metrics_app() -> object:
    """Create the Prometheus metrics ASGI app.

    Returns
    -------
    object
        An ASGI application that serves Prometheus metrics at ``/metrics``.
    """
    return make_asgi_app(registry=REGISTRY)


# ---------------------------------------------------------------------------
# Utility: record HTTP request
# ---------------------------------------------------------------------------


def record_http_request(method: str, path: str, status: int, duration_seconds: float) -> None:
    """Record an HTTP request in Prometheus metrics.

    Parameters
    ----------
    method:
        HTTP method (GET, POST, etc.).
    path:
        Request path (e.g., "/v1/chat/completions").
    status:
        HTTP status code.
    duration_seconds:
        Request duration in seconds.
    """
    # Normalize path to avoid cardinality explosion
    normalized_path = _normalize_path(path)

    http_requests_total.labels(method=method, path=normalized_path, status=str(status)).inc()
    http_request_duration_seconds.labels(method=method, path=normalized_path).observe(duration_seconds)


def record_llm_request(
    backend: str,
    model: str,
    cached: bool,
    tokens: int,
    cost: float,
    savings: float,
) -> None:
    """Record an LLM request in Prometheus metrics.

    Parameters
    ----------
    backend:
        Backend name (e.g., "ollama", "openai").
    model:
        Model identifier.
    cached:
        Whether the response was cached.
    tokens:
        Total tokens (input + output).
    cost:
        Actual cost in USD.
    savings:
        Cloud-equivalent savings in USD.
    """
    llm_requests_total.labels(backend=backend, model=model, cached=str(cached).lower()).inc()
    llm_tokens_total.labels(backend=backend, model=model).inc(tokens)
    llm_cost_usd_total.labels(backend=backend).inc(cost)
    llm_savings_usd_total.inc(savings)


def record_cache_eviction(tier: str, count: int = 1) -> None:
    """Record cache evictions in Prometheus.

    Parameters
    ----------
    tier:
        Cache tier: "exact", "namespace", or "vcache".
    count:
        Number of entries evicted.
    """
    cache_evictions_total.labels(tier=tier).inc(count)


# ---------------------------------------------------------------------------
# Path normalization
# ---------------------------------------------------------------------------


def _normalize_path(path: str) -> str:
    """Normalize request path to reduce cardinality.

    Replaces UUIDs, IDs, and other variable segments with placeholders.
    """
    import re

    # Remove query string
    path = path.split("?")[0]

    # Replace UUIDs
    path = re.sub(r"/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", "/{uuid}", path)

    # Replace numeric IDs
    path = re.sub(r"/\d+", "/{id}", path)

    return path
