import time
from collections.abc import Callable
from typing import Any

from fastapi import Request, Response
from prometheus_client import Counter, Gauge, Histogram

REQUEST_COUNT = Counter(
    "pip_http_requests_total",
    "Total HTTP requests",
    ["method", "endpoint", "status_code"],
)

REQUEST_DURATION = Histogram(
    "pip_http_request_duration_seconds",
    "HTTP request duration in seconds",
    ["method", "endpoint"],
    buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
)

REQUESTS_IN_PROGRESS = Gauge(
    "pip_http_requests_in_progress",
    "HTTP requests currently in progress",
    ["method", "endpoint"],
)

DB_QUERY_DURATION = Histogram(
    "pip_db_query_duration_seconds",
    "Database query duration in seconds",
    ["operation"],
    buckets=[0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0],
)

CONNECTOR_OPERATIONS = Counter(
    "pip_connector_operations_total",
    "Total connector operations",
    ["connector_type", "operation", "status"],
)

SYNC_JOBS = Counter(
    "pip_sync_jobs_total",
    "Total sync jobs",
    ["strategy", "status"],
)

SYNC_DURATION = Histogram(
    "pip_sync_duration_seconds",
    "Sync job duration in seconds",
    ["strategy"],
    buckets=[1.0, 5.0, 10.0, 30.0, 60.0, 300.0, 600.0, 1800.0],
)

ACTIVE_CONNECTIONS = Gauge(
    "pip_active_connections",
    "Active infrastructure connections",
    ["type"],
)

CACHE_OPERATIONS = Counter(
    "pip_cache_operations_total",
    "Cache operations",
    ["operation", "result"],
)

RESERVATION_OPERATIONS = Counter(
    "pip_reservation_operations_total",
    "Reservation operations",
    ["operation", "status"],
)


async def metrics_middleware(request: Request, call_next: Callable) -> Response:
    if request.url.path == "/metrics" or request.url.path.startswith("/docs") or request.url.path.startswith("/openapi"):
        return await call_next(request)

    method = request.method
    endpoint = request.url.path

    REQUESTS_IN_PROGRESS.labels(method=method, endpoint=endpoint).inc()

    start_time = time.perf_counter()
    try:
        response = await call_next(request)
        status_code = response.status_code
    except Exception:
        status_code = 500
        raise
    finally:
        duration = time.perf_counter() - start_time
        REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=status_code).inc()
        REQUEST_DURATION.labels(method=method, endpoint=endpoint).observe(duration)
        REQUESTS_IN_PROGRESS.labels(method=method, endpoint=endpoint).dec()

    return response
