from __future__ import annotations

import logging
import time

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

from app.db import get_pool
from app.services.geo import geo_resolver
from app.services.ws_hub import hub

logger = logging.getLogger(__name__)


class LoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next) -> Response:
        # Skip WebSocket upgrade requests on /ws/ paths
        if request.url.path.startswith("/ws/"):
            return await call_next(request)

        start = time.monotonic()
        ip = request.client.host if request.client else "unknown"

        response = await call_next(request)

        latency_ms = (time.monotonic() - start) * 1000.0
        geo = geo_resolver.resolve(ip)

        try:
            pool = get_pool()
            row = await pool.fetchrow(
                """
                INSERT INTO access_logs
                    (ip, method, path, status_code, latency_ms,
                     country, city, latitude, longitude)
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
                RETURNING id, created_at
                """,
                ip,
                request.method,
                request.url.path,
                response.status_code,
                latency_ms,
                geo.country,
                geo.city,
                geo.latitude,
                geo.longitude,
            )

            log_dict = {
                "id": row["id"],
                "ip": ip,
                "method": request.method,
                "path": request.url.path,
                "status_code": response.status_code,
                "latency_ms": latency_ms,
                "country": geo.country,
                "city": geo.city,
                "latitude": geo.latitude,
                "longitude": geo.longitude,
                "created_at": row["created_at"].isoformat(),
            }

            try:
                await hub.broadcast(log_dict)
            except Exception as exc:
                logger.error("WebSocket broadcast failed: %s", exc)

        except Exception as exc:
            logger.error("Failed to write access log: %s", exc)

        return response
