"""
Middleware for request logging and tracking.

Implements correlation ID tracking for requests and comprehensive logging
following 2026 FastAPI best practices.
"""

import logging
import time
import uuid
from typing import Callable

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp

logger = logging.getLogger(__name__)


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """
    Middleware to log all HTTP requests with timing and correlation IDs.

    Features:
    - Generates unique correlation ID for each request
    - Logs request method, path, and client IP
    - Measures and logs request processing time
    - Logs response status code
    - Adds correlation ID to response headers for tracing
    """

    async def dispatch(
        self, request: Request, call_next: Callable
    ) -> Response:
        # Generate correlation ID for request tracking
        correlation_id = str(uuid.uuid4())
        request.state.correlation_id = correlation_id

        # Get client IP
        client_host = request.client.host if request.client else "unknown"

        # Log incoming request
        logger.info(
            f"Request started - "
            f"method={request.method} "
            f"path={request.url.path} "
            f"client={client_host} "
            f"correlation_id={correlation_id}"
        )

        # Process request and measure time
        start_time = time.time()

        try:
            response = await call_next(request)
            process_time = time.time() - start_time

            # Add correlation ID to response headers
            response.headers["X-Correlation-ID"] = correlation_id
            response.headers["X-Process-Time"] = str(process_time)

            # Log response
            logger.info(
                f"Request completed - "
                f"method={request.method} "
                f"path={request.url.path} "
                f"status={response.status_code} "
                f"duration={process_time:.3f}s "
                f"correlation_id={correlation_id}"
            )

            return response

        except Exception as exc:
            process_time = time.time() - start_time

            # Log error
            logger.error(
                f"Request failed - "
                f"method={request.method} "
                f"path={request.url.path} "
                f"duration={process_time:.3f}s "
                f"correlation_id={correlation_id} "
                f"error={str(exc)}",
                exc_info=True
            )

            # Re-raise exception to be handled by FastAPI
            raise


class ErrorLoggingMiddleware(BaseHTTPMiddleware):
    """
    Middleware to catch and log unhandled exceptions.

    Ensures all exceptions are logged before being returned to the client,
    providing full stack traces for debugging.
    """

    async def dispatch(
        self, request: Request, call_next: Callable
    ) -> Response:
        try:
            response = await call_next(request)
            return response
        except Exception as exc:
            correlation_id = getattr(request.state, "correlation_id", "unknown")

            logger.error(
                f"Unhandled exception - "
                f"method={request.method} "
                f"path={request.url.path} "
                f"correlation_id={correlation_id}",
                exc_info=True
            )

            # Re-raise to let FastAPI handle the response
            raise
