"""
NEXIUM Middleware - Middleware system for request/response processing
Author: Juste Elysée MALANDILA
"""

from typing import Callable, Optional, Any
from dataclasses import dataclass


@dataclass
class Middleware:
    """Middleware wrapper."""
    handler: Callable
    name: Optional[str] = None
    priority: int = 0
    
    async def __call__(self, request, call_next):
        """Execute middleware."""
        return await self.handler(request, call_next)


def middleware(name: Optional[str] = None, priority: int = 0):
    """
    Middleware decorator.
    
    Example:
        >>> @middleware(name="auth")
        >>> async def auth_middleware(request, call_next):
        >>>     if not request.headers.get("Authorization"):
        >>>         raise Unauthorized()
        >>>     response = await call_next(request)
        >>>     return response
    """
    def decorator(func: Callable):
        func._middleware_info = {
            "name": name or func.__name__,
            "priority": priority,
        }
        return func
    return decorator


class MiddlewareStack:
    """Middleware execution stack."""
    
    def __init__(self):
        self.middlewares: list[Middleware] = []
    
    def add(self, middleware: Middleware):
        """Add middleware to stack."""
        self.middlewares.append(middleware)
        # Sort by priority (higher first)
        self.middlewares.sort(key=lambda m: m.priority, reverse=True)
    
    async def execute(self, request, final_handler):
        """Execute middleware stack."""
        async def call_next(req):
            if not self.middlewares:
                return await final_handler(req)
            
            middleware = self.middlewares[0]
            remaining = self.middlewares[1:]
            
            async def next_handler(r):
                stack = MiddlewareStack()
                stack.middlewares = remaining
                return await stack.execute(r, final_handler)
            
            return await middleware(req, next_handler)
        
        return await call_next(request)
