"""
Middleware Module - Gom Auth + Rate Limit
Singleton Pattern cho cả 2 services
"""
from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from fastapi import Request

from common.jwt_auth import decode_token
from config import DISABLE_AUTH
from common.memos_core.services import PersonalAccessTokenService

if TYPE_CHECKING:
    from fastapi import FastAPI

logger = logging.getLogger(__name__)


# =============================================================================
# CONFIGURATION
# =============================================================================

# Public endpoints - không cần auth
PUBLIC_PATHS = {
    "/",
    "/health",
    "/docs",
    "/openapi.json",
    "/redoc",
}

# Public path prefixes
PUBLIC_PATH_PREFIXES = [
    "/static",
    "/mock",
    "/api/test",  # debug/test endpoints - no auth required
]


# =============================================================================
# AUTH + RATE LIMIT MIDDLEWARE CLASS
# =============================================================================

# Paths that need rate limit check
RATE_LIMITED_PATHS = [
    "/api/agent/chat",
]

class CuCuAuthMiddleware:
    """
    Pure ASGI Authentication + Rate Limit Middleware.
    
    Replaces BaseHTTPMiddleware to avoid run_in_threadpool overhead (2-5ms/req).
    
    Flow:
    1. Frontend gửi request với Authorization: Bearer <cucu_token>
    2. Middleware verify token với Clerk → extract customer_id
    3. Check message rate limit (Guest: 10, User: 100)
    4. Attach user info vào request.state
    5. Routes lấy trực tiếp từ request.state
    """

    def __init__(self, app):
        self.app = app

    async def __call__(self, scope, receive, send):
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        request = Request(scope)
        path = request.url.path
        method = request.method

        # Temporary bypass: populate mock auth state when DISABLE_AUTH=true
        if DISABLE_AUTH:
            auth_header = request.headers.get("Authorization")
            mock_id = "testuser_local"
            if auth_header and auth_header.startswith("Bearer "):
                token = auth_header.replace("Bearer ", "")
                try:
                    payload = decode_token(token)
                    if payload and "sub" in payload:
                        mock_id = str(payload.get("sub"))
                except Exception:
                    if len(token) < 50:
                        mock_id = token
            scope["state"]["user"] = {"sub": mock_id}
            scope["state"]["user_id"] = mock_id
            scope["state"]["is_authenticated"] = True
            scope["state"]["token"] = auth_header.replace("Bearer ", "") if auth_header else ""
            await self.app(scope, receive, send)
            return

        # ✅ Allow OPTIONS requests (CORS preflight)
        if method == "OPTIONS":
            await self.app(scope, receive, send)
            return

        # Skip public endpoints
        if path in PUBLIC_PATHS:
            await self.app(scope, receive, send)
            return

        # Skip public path prefixes
        if any(path.startswith(prefix) for prefix in PUBLIC_PATH_PREFIXES):
            await self.app(scope, receive, send)
            return

        # =====================================================================
        # STEP 1: AUTHENTICATION (Local JWT)
        # =====================================================================
        try:
            auth_header = request.headers.get("Authorization")
            device_id = request.headers.get("device_id", "")

            # --- TRƯỜNG HỢP 1: KHÔNG CÓ TOKEN -> GUEST ---
            if not auth_header or not auth_header.startswith("Bearer "):
                scope["state"]["user"] = None
                scope["state"]["user_id"] = None
                scope["state"]["is_authenticated"] = False
                scope["state"]["device_id"] = device_id
            else:
                # --- TRƯỜNG HỢP 2: CÓ TOKEN -> VERIFY JWT or PAT ---
                token = auth_header.replace("Bearer ", "")
                jwt_success = False
                try:
                    payload = decode_token(token)
                    if payload and "sub" in payload:
                        user_id = payload.get("sub")
                        scope["state"]["user"] = payload
                        scope["state"]["user_id"] = str(user_id)
                        scope["state"]["token"] = token
                        scope["state"]["is_authenticated"] = True
                        scope["state"]["device_id"] = device_id or str(user_id)
                        logger.debug("✅ Local JWT Auth Success: user_id=%s", user_id)
                        jwt_success = True
                    else:
                        logger.warning("⚠️ JWT token missing sub, trying PAT")
                except Exception as e:
                    logger.warning("⚠️ JWT decode error: %s, trying PAT", e)

                # If JWT failed, try Personal Access Token
                if not jwt_success:
                    try:
                        pat_service = PersonalAccessTokenService()
                        pat_verify = await pat_service.verify_token(token)
                        if pat_verify:
                            user_id = pat_verify["user_id"]
                            scope["state"]["user"] = {"sub": user_id}
                            scope["state"]["user_id"] = str(user_id)
                            scope["state"]["token"] = token
                            scope["state"]["is_authenticated"] = True
                            scope["state"]["device_id"] = device_id or str(user_id)
                            logger.debug("✅ PAT Auth Success: user_id=%s", user_id)
                        else:
                            # PAT verification failed -> Guest
                            logger.warning("⚠️ PAT verification failed -> Guest Mode")
                            scope["state"]["user"] = None
                            scope["state"]["user_id"] = None
                            scope["state"]["is_authenticated"] = False
                            scope["state"]["device_id"] = device_id
                    except Exception as pat_e:
                        logger.error("❌ PAT Auth Error: %s -> Guest Mode", pat_e)
                        scope["state"]["user"] = None
                        scope["state"]["user_id"] = None
                        scope["state"]["is_authenticated"] = False
                        scope["state"]["device_id"] = device_id

        except Exception as e:
            logger.error(f"❌ Middleware Auth Error: {e}")
            scope["state"]["user"] = None
            scope["state"]["user_id"] = None
            scope["state"]["is_authenticated"] = False
            scope["state"]["device_id"] = request.headers.get("device_id", "")

        # =====================================================================
        # STEP 2: RATE LIMIT CHECK (Chỉ cho các path cần limit)
        # =====================================================================
        if path in RATE_LIMITED_PATHS:
            try:
                from common.message_limit import message_limit_service
                from fastapi.responses import JSONResponse
                
                # Lấy identity_key làm rate limit key
                is_authenticated = scope["state"].get("is_authenticated", False)
                if is_authenticated and scope["state"].get("user_id"):
                    rate_limit_key = scope["state"]["user_id"]
                else:
                    rate_limit_key = scope["state"].get("device_id", "")
                
                if rate_limit_key:
                    can_send, limit_info = await message_limit_service.check_limit(
                        identity_key=rate_limit_key,
                        is_authenticated=is_authenticated,
                    )
                    
                    # Lưu limit_info vào state để route có thể dùng
                    scope["state"]["limit_info"] = limit_info
                    
                    if not can_send:
                        logger.warning(
                            "⚠️ Rate Limit Exceeded: %s | used=%s/%s",
                            rate_limit_key,
                            limit_info["used"],
                            limit_info["limit"],
                        )
                        response = JSONResponse(
                            status_code=429,
                            content={
                                "status": "error",
                                "error_code": "MESSAGE_LIMIT_EXCEEDED",
                                "message": limit_info["message"],
                                "require_login": limit_info["require_login"],
                                "limit_info": {
                                    "limit": limit_info["limit"],
                                    "used": limit_info["used"],
                                    "remaining": limit_info["remaining"],
                                    "reset_seconds": limit_info["reset_seconds"],
                                },
                            },
                        )
                        await response(scope, receive, send)
                        return
                else:
                    logger.warning(f"⚠️ No identity_key for rate limiting")
                    
            except Exception as e:
                logger.error(f"❌ Rate Limit Check Error: {e}")
                # Cho phép request tiếp tục nếu lỗi rate limit
            
        await self.app(scope, receive, send)


# =============================================================================
# MIDDLEWARE MANAGER - Singleton to manage all middlewares
# =============================================================================

class MiddlewareManager:
    """
    Middleware Manager - Singleton Pattern
    Quản lý và setup tất cả middlewares cho FastAPI app
    
    Usage:
        from common.middleware import middleware_manager
        
        app = FastAPI()
        middleware_manager.setup(app, enable_auth=True, enable_rate_limit=True)
    """
    
    _instance: MiddlewareManager | None = None
    _initialized: bool = False
    
    def __new__(cls) -> MiddlewareManager:
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self) -> None:
        if MiddlewareManager._initialized:
            return
        
        self._auth_enabled = False
        self._rate_limit_enabled = False
        
        MiddlewareManager._initialized = True
        logger.info("✅ MiddlewareManager initialized")
    
    def setup(
        self,
        app: FastAPI,
        *,
        enable_auth: bool = True,
        enable_rate_limit: bool = True,
        enable_cors: bool = True,
        cors_origins: list[str] | None = None,
    ) -> None:
        """
        Setup tất cả middlewares cho FastAPI app.
        
        Args:
            app: FastAPI application
            enable_auth: Bật CuCu authentication middleware
            enable_rate_limit: Bật rate limiting
            enable_cors: Bật CORS middleware
            cors_origins: List origins cho CORS (default: ["*"])
        
        Note:
            Thứ tự middleware quan trọng! Middleware thêm sau sẽ chạy TRƯỚC.
            Order: CORS → Auth → RateLimit → SlowAPI
        """
        # 1. CORS Middleware (thêm cuối cùng để chạy đầu tiên)
        if enable_cors:
            self._setup_cors(app, cors_origins or ["*"])
        
        # 2. Auth Middleware
        if enable_auth:
            self._setup_auth(app)
        
        # 3. Rate Limit Middleware
        if enable_rate_limit:
            self._setup_rate_limit(app)
        
        logger.info(
            f"✅ Middlewares configured: "
            f"CORS={enable_cors}, Auth={enable_auth}, RateLimit={enable_rate_limit}"
        )
    
    def _setup_cors(self, app: FastAPI, origins: list[str]) -> None:
        """Setup CORS middleware."""
        from fastapi.middleware.cors import CORSMiddleware
        
        app.add_middleware(
            CORSMiddleware,
            allow_origins=origins,
            allow_credentials=True,
            allow_methods=["*"],
            allow_headers=["*"],
        )
        logger.info(f"✅ CORS middleware enabled (origins: {origins})")
    
    def _setup_auth(self, app: FastAPI) -> None:
        """Setup CuCu auth middleware."""
        app.add_middleware(CuCuAuthMiddleware)
        self._auth_enabled = True
        logger.info("✅ CuCu Auth middleware enabled")
    
    def _setup_rate_limit(self, app: FastAPI) -> None:
        """Setup rate limiting."""
        from common.rate_limit import rate_limit_service
        
        rate_limit_service.setup(app)
        self._rate_limit_enabled = True
        logger.info("✅ Rate Limit middleware enabled")
    
    @property
    def is_auth_enabled(self) -> bool:
        return self._auth_enabled
    
    @property
    def is_rate_limit_enabled(self) -> bool:
        return self._rate_limit_enabled


# =============================================================================
# SINGLETON INSTANCE
# =============================================================================

middleware_manager = MiddlewareManager()
