from __future__ import annotations

import logging
from collections.abc import Callable

from fastapi import HTTPException, Request, status
from starlette.middleware.base import BaseHTTPMiddleware

from common.clerk_auth import verify_clerk_token

logger = logging.getLogger(__name__)

# Public endpoints that don't require authentication
PUBLIC_PATHS = {
    "/",
    "/health",
    "/docs",
    "/openapi.json",
    "/redoc",
}

# Paths that start with these prefixes are public
PUBLIC_PATH_PREFIXES = [
    # Socket.IO removed - using SSE instead
]


class ClerkAuthMiddleware(BaseHTTPMiddleware):
    """
    Clerk Authentication Middleware
    Tự động verify Clerk JWT tokens cho protected endpoints.
    Attach user info vào request.state để routes có thể sử dụng.

    Flow:
    1. Frontend gửi request với Authorization: Bearer <clerk_token>
    2. Middleware verify token và extract user_id
    3. Attach user info vào request.state.user và request.state.user_id
    4. Routes lấy trực tiếp từ request.state (không cần Depends)
    """

    async def dispatch(self, request: Request, call_next: Callable):
        path = request.url.path
        method = request.method

        # ✅ Allow OPTIONS requests (CORS preflight) - không cần auth
        if method == "OPTIONS":
            return await call_next(request)

        # Skip public endpoints - không cần auth
        if path in PUBLIC_PATHS:
            return await call_next(request)

        # Skip paths with public prefixes
        if any(path.startswith(prefix) for prefix in PUBLIC_PATH_PREFIXES):
            return await call_next(request)

        # ✅ For protected endpoints, verify Clerk token và raise 401 nếu không có
        try:
            # Get token from Authorization header
            auth_header = request.headers.get("Authorization")

            # ========== DEV MODE: Bypass auth nếu có X-Dev-User-Id header ==========
            # ⚠️ CHỈ DÙNG CHO TEST/DEV - XÓA TRƯỚC KHI DEPLOY PRODUCTION
            dev_user_id = request.headers.get("X-Dev-User-Id")
            if dev_user_id:
                logger.warning(f"⚠️ DEV MODE: Using X-Dev-User-Id={dev_user_id} (bypassing Clerk auth)")
                request.state.user = {"user_id": dev_user_id, "clerk_user_id": dev_user_id}
                request.state.user_id = dev_user_id
                request.state.clerk_token = None
                return await call_next(request)

            if not auth_header or not auth_header.startswith("Bearer "):
                # Log để debug
                logger.warning(f"⚠️ No Authorization header for {method} {path}. Headers: {dict(request.headers)}")
                # Không có token → raise 401
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="Authentication required. Please provide a valid Clerk token in Authorization header.",
                )

            # Extract token
            token = auth_header.replace("Bearer ", "")
            from fastapi.security import HTTPAuthorizationCredentials

            credentials = HTTPAuthorizationCredentials(scheme="Bearer", credentials=token)

            # ✅ Verify token và extract user info
            user = await verify_clerk_token(request, credentials)

            # ✅ Attach user info vào request.state để routes sử dụng
            request.state.user = user
            request.state.user_id = user.get("user_id") or user.get("clerk_user_id")
            request.state.clerk_token = token  # Lưu token để forward cho Supabase RLS

            logger.debug(f"✅ Authenticated user {request.state.user_id} for {path}")

        except HTTPException:
            # Re-raise HTTPException (401, etc.)
            raise
        except Exception as e:
            logger.error(f"❌ Clerk auth verification failed for {path}: {e}")
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token")

        return await call_next(request)
