"""
Prometheus metrics.

Exposes /metrics on a separate port (settings.METRICS_PORT) rather than
mixing it into the main API port — this is standard practice so metrics
scraping traffic is isolated from client-facing traffic and can have
different access controls (typically metrics endpoints are firewalled
to internal monitoring infra only, never exposed publicly).
"""

import time

from fastapi import Request
from prometheus_client import Counter, Histogram
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response

REQUEST_COUNT = Counter(
    "http_requests_total",
    "Total HTTP requests",
    ["method", "path", "status_code"],
)

REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds",
    "HTTP request latency in seconds",
    ["method", "path"],
    buckets=(0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30),
)

ANALYSIS_QUEUED = Counter(
    "crop_analysis_queued_total",
    "Total crop analysis tasks queued",
    ["crop", "district"],
)

ANALYSIS_CACHE_HITS = Counter(
    "crop_analysis_cache_hits_total",
    "Total crop analysis requests served from cache",
)

MODEL_DEGRADED = Counter(
    "model_degraded_total",
    "Count of times a specific model returned a degraded result",
    ["model_name"],
)


class PrometheusMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next) -> Response:
        start = time.perf_counter()
        response = await call_next(request)
        elapsed = time.perf_counter() - start

        # Use the route template, not the raw path, so /tasks/{id} for
        # 10,000 different ids collapses into one metric series rather
        # than creating unbounded cardinality in Prometheus.
        route = request.scope.get("route")
        path_label = route.path if route else request.url.path

        REQUEST_COUNT.labels(
            method=request.method, path=path_label, status_code=response.status_code
        ).inc()
        REQUEST_LATENCY.labels(method=request.method, path=path_label).observe(elapsed)

        return response
