"""
Logging Middleware for FastAPI

Automatically logs all incoming requests and outgoing responses with comprehensive details.
"""

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
import time
import json
from typing import Callable

from app.utils.logger import get_logger

logger = get_logger("middleware")
access_logger = get_logger("access")


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """
    Middleware to log all HTTP requests and responses with detailed information.
    """

    def __init__(self, app: ASGIApp):
        super().__init__(app)

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        # Start timing
        start_time = time.time()

        # Extract request details
        request_id = id(request)  # Unique ID for this request
        method = request.method
        url = str(request.url)
        client_host = request.client.host if request.client else "unknown"
        user_agent = request.headers.get("user-agent", "unknown")

        # Log incoming request
        access_logger.info(
            f"[{request_id}] {method} {url} | Client: {client_host} | User-Agent: {user_agent[:50]}"
        )

        # Try to log request body for POST/PUT/PATCH (be careful with large bodies)
        if method in ["POST", "PUT", "PATCH"]:
            try:
                content_type = request.headers.get("content-type", "")
                if "application/json" in content_type:
                    # For JSON, we can log it
                    body = await request.body()
                    if len(body) < 1000:  # Only log if less than 1KB
                        try:
                            body_json = json.loads(body)
                            # Don't log passwords or sensitive data
                            safe_body = {k: "***HIDDEN***" if "password" in k.lower() or "token" in k.lower() else v
                                       for k, v in body_json.items()}
                            logger.debug(f"[{request_id}] Request Body: {json.dumps(safe_body)}")
                        except:
                            logger.debug(f"[{request_id}] Request Body: {len(body)} bytes")
                    else:
                        logger.debug(f"[{request_id}] Request Body: {len(body)} bytes (too large to log)")

                    # Re-create request with body for downstream handlers
                    async def receive():
                        return {"type": "http.request", "body": body}
                    request._receive = receive
            except Exception as e:
                logger.warning(f"[{request_id}] Could not log request body: {e}")

        # Process request
        try:
            response = await call_next(request)

            # Calculate duration
            duration = time.time() - start_time

            # Log response
            status_code = response.status_code
            log_level = "info"

            if status_code >= 500:
                log_level = "error"
            elif status_code >= 400:
                log_level = "warning"
            elif duration > 5.0:
                log_level = "warning"  # Slow request

            log_message = (
                f"[{request_id}] {method} {url} | "
                f"Status: {status_code} | "
                f"Duration: {duration:.3f}s | "
                f"Client: {client_host}"
            )

            if duration > 5.0:
                log_message += " (SLOW REQUEST)"

            getattr(access_logger, log_level)(log_message)

            return response

        except Exception as e:
            # Log error
            duration = time.time() - start_time
            logger.error(
                f"[{request_id}] {method} {url} | "
                f"ERROR: {type(e).__name__}: {str(e)} | "
                f"Duration: {duration:.3f}s | "
                f"Client: {client_host}"
            )
            raise


class ErrorLoggingMiddleware(BaseHTTPMiddleware):
    """
    Middleware to catch and log all unhandled exceptions with full context.
    """

    def __init__(self, app: ASGIApp):
        super().__init__(app)

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        try:
            return await call_next(request)
        except Exception as e:
            # Log comprehensive error details
            import traceback

            error_details = {
                "error_type": type(e).__name__,
                "error_message": str(e),
                "method": request.method,
                "url": str(request.url),
                "client": request.client.host if request.client else "unknown",
                "headers": dict(request.headers),
                "traceback": traceback.format_exc()
            }

            logger.error(
                f"Unhandled Exception in {request.method} {request.url}\n"
                f"Error Type: {error_details['error_type']}\n"
                f"Error Message: {error_details['error_message']}\n"
                f"Client: {error_details['client']}\n"
                f"Full Traceback:\n{error_details['traceback']}"
            )

            # Re-raise to let FastAPI handle it
            raise
