"""Shared middleware and exception handlers."""

from __future__ import annotations

import logging
import time

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from common.types import ErrorResponse

logger = logging.getLogger(__name__)


def add_exception_handlers(app: FastAPI) -> None:
    """Register uniform error responses."""

    @app.exception_handler(Exception)
    async def unhandled_exception_handler(_: Request, exc: Exception) -> JSONResponse:
        logger.exception("Unhandled exception: %s", exc)
        payload = ErrorResponse(error="internal_error", detail=str(exc)).model_dump()
        return JSONResponse(status_code=500, content=payload)


def add_cors(
    app: FastAPI,
    origins: list[str] | None = None,
) -> None:
    """Add CORS middleware with configurable origins."""
    allowed = origins or ["*"]
    app.add_middleware(
        CORSMiddleware,
        allow_origins=allowed,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )


def add_rate_limiting(app: FastAPI, default_limit: str = "60/minute") -> None:
    """Add per-IP rate limiting via slowapi."""
    try:
        from slowapi import Limiter, _rate_limit_exceeded_handler
        from slowapi.errors import RateLimitExceeded
        from slowapi.util import get_remote_address

        limiter = Limiter(key_func=get_remote_address, default_limits=[default_limit])
        app.state.limiter = limiter
        app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
    except ImportError:
        logger.debug("slowapi not installed — rate limiting disabled")


def add_request_logging(app: FastAPI) -> None:
    """Add request/response logging middleware."""

    @app.middleware("http")
    async def log_requests(request: Request, call_next):
        start = time.perf_counter()
        response = await call_next(request)
        elapsed_ms = (time.perf_counter() - start) * 1000
        logger.info(
            "%s %s %d %.1fms",
            request.method,
            request.url.path,
            response.status_code,
            elapsed_ms,
        )
        return response


def configure_structured_logging(log_level: str = "INFO") -> None:
    """Configure structured logging via structlog if available, else stdlib."""
    try:
        import structlog

        structlog.configure(
            processors=[
                structlog.contextvars.merge_contextvars,
                structlog.processors.add_log_level,
                structlog.processors.StackInfoRenderer(),
                structlog.dev.set_exc_info,
                structlog.processors.TimeStamper(fmt="iso"),
                structlog.dev.ConsoleRenderer(),
            ],
            wrapper_class=structlog.make_filtering_bound_logger(
                logging.getLevelName(log_level.upper()),
            ),
            context_class=dict,
            logger_factory=structlog.PrintLoggerFactory(),
            cache_logger_on_first_use=True,
        )
    except ImportError:
        logging.basicConfig(
            level=getattr(logging, log_level.upper(), logging.INFO),
            format="%(asctime)s %(levelname)-8s %(name)s — %(message)s",
        )
