import uuid
import logging
from flask import Flask, request, g

from . import request_id_var, get_excluded_endpoints

logger = logging.getLogger(__name__)
RequestIdHeader = "X-Request-ID"


class FlaskRequestIdMiddleware:
    """
    Flask middleware to handle the request ID and provide comprehensive debugging.
    It checks for a 'X-Request-ID' header in the incoming request.
    If the header is present, its value is used as the request ID.
    If not, a new UUID is generated.
    The request ID is then stored in a context variable.
    Provides detailed logging for incoming requests and outgoing responses.
    
    Usage:
        from flask import Flask
        from litewave_logger import setup_logging
        from litewave_logger.flask_middleware import FlaskRequestIdMiddleware
        
        app = Flask(__name__)
        setup_logging(excluded_endpoints=['/health'])
        FlaskRequestIdMiddleware(app)
    """
    
    def __init__(self, app: Flask = None):
        """
        Initialize the middleware.
        
        Args:
            app: Flask application instance. If provided, init_app() is called automatically.
        """
        self.app = app
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app: Flask):
        """
        Initialize the middleware with a Flask application.
        Supports Flask's application factory pattern.
        
        Args:
            app: Flask application instance.
        """
        app.before_request(self._before_request)
        app.after_request(self._after_request)
    
    def _before_request(self):
        """
        Handler called before each request.
        Sets up request ID and logs incoming request.
        """
        # Get or generate request ID
        request_id = request.headers.get(RequestIdHeader)
        if not request_id:
            request_id = str(uuid.uuid4())
        
        # Store request ID in Flask's g object for easy access in views
        g.request_id = request_id
        
        # Set request ID in context variable (for logging filter)
        request_id_var.set(request_id)
        
        # Check if this endpoint should be excluded from logging
        excluded_endpoints = get_excluded_endpoints()
        path = request.path
        g.should_log = path not in excluded_endpoints
        
        if g.should_log:
            logger.info("request received", extra={
                "method": request.method,
                "path": path
            })
    
    def _after_request(self, response):
        """
        Handler called after each request.
        Adds request ID to response headers and logs response.
        
        Args:
            response: Flask response object.
            
        Returns:
            Modified response with request ID header.
        """
        # Add request ID to response headers
        request_id = getattr(g, 'request_id', None)
        if request_id:
            response.headers[RequestIdHeader] = request_id
        
        # Log response details only if endpoint is not excluded
        should_log = getattr(g, 'should_log', True)
        if should_log:
            logger.info("response sent", extra={
                "status_code": response.status_code
            })
        
        return response


def get_request_id():
    """
    Utility function to get the current request ID from Flask's g object.
    
    Returns:
        The current request ID or None if not available.
    """
    return getattr(g, 'request_id', None)


__all__ = ["FlaskRequestIdMiddleware", "get_request_id"]

