"""
⚡ FastAPI Bottleneck Middleware
================================
Thêm vào server.py để tự động đo latency từng request.

Dùng:
  1. Import vào server.py:
     from common.profiler_middleware import ProfilerMiddleware
  2. Thêm middleware:
     app.add_middleware(ProfilerMiddleware)
  3. Xem báo cáo:
     GET /debug/profiler/stats
     GET /debug/profiler/slow   (các request chậm nhất)
     GET /debug/profiler/reset
"""

import logging
import time
from collections import deque
from dataclasses import dataclass, field
from statistics import mean, median

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse

logger = logging.getLogger("profiler.middleware")


@dataclass
class RequestMetric:
    path: str
    method: str
    duration: float
    status_code: int
    timestamp: float


class ProfilerMiddleware(BaseHTTPMiddleware):
    """Middleware đo latency từng request + expose metrics endpoint."""

    # Class-level storage (shared across instances)
    _metrics: deque = deque(maxlen=1000)  # Last 1000 requests
    _slow_threshold: float = 5.0  # Seconds

    async def dispatch(self, request: Request, call_next):
        # Skip profiler endpoints
        if request.url.path.startswith("/debug/profiler"):
            return await self._handle_profiler_endpoint(request)

        start = time.perf_counter()

        response = await call_next(request)

        duration = time.perf_counter() - start

        metric = RequestMetric(
            path=request.url.path,
            method=request.method,
            duration=duration,
            status_code=response.status_code,
            timestamp=time.time(),
        )
        self._metrics.append(metric)

        # Log slow requests
        if duration > self._slow_threshold:
            logger.warning(
                f"🐌 SLOW REQUEST: {request.method} {request.url.path} "
                f"took {duration:.2f}s (>{self._slow_threshold}s)"
            )

        # Add timing header
        response.headers["X-Response-Time"] = f"{duration:.3f}s"

        return response

    async def _handle_profiler_endpoint(self, request: Request) -> JSONResponse:
        path = request.url.path

        if path == "/debug/profiler/stats":
            return self._get_stats()
        elif path == "/debug/profiler/slow":
            return self._get_slow_requests()
        elif path == "/debug/profiler/reset":
            self._metrics.clear()
            return JSONResponse({"status": "reset", "message": "Metrics cleared"})

        return JSONResponse({"error": "Unknown profiler endpoint"}, status_code=404)

    def _get_stats(self) -> JSONResponse:
        if not self._metrics:
            return JSONResponse({"message": "No data yet"})

        metrics = list(self._metrics)
        durations = [m.duration for m in metrics]

        # Group by path
        path_stats = {}
        for m in metrics:
            key = f"{m.method} {m.path}"
            if key not in path_stats:
                path_stats[key] = []
            path_stats[key].append(m.duration)

        path_summary = {}
        for path, times in sorted(path_stats.items(), key=lambda x: -max(x[1])):
            path_summary[path] = {
                "count": len(times),
                "avg": round(mean(times), 3),
                "median": round(median(times), 3),
                "min": round(min(times), 3),
                "max": round(max(times), 3),
            }

        return JSONResponse({
            "total_requests": len(metrics),
            "overall": {
                "avg": round(mean(durations), 3),
                "median": round(median(durations), 3),
                "min": round(min(durations), 3),
                "max": round(max(durations), 3),
            },
            "by_path": path_summary,
            "slow_count": sum(1 for d in durations if d > self._slow_threshold),
        })

    def _get_slow_requests(self) -> JSONResponse:
        slow = [
            {
                "path": m.path,
                "method": m.method,
                "duration": round(m.duration, 3),
                "status": m.status_code,
                "timestamp": m.timestamp,
            }
            for m in self._metrics
            if m.duration > self._slow_threshold
        ]
        slow.sort(key=lambda x: -x["duration"])
        return JSONResponse({"threshold": self._slow_threshold, "slow_requests": slow[:50]})
