"""
Authentication and Authorization Module

Integrates with DRF's permission system and provides OAuth2/OIDC support
for agent authentication in MCP context.
"""

import logging
from typing import Any, Optional

from django.contrib.auth.models import AnonymousUser, User
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

logger = logging.getLogger(__name__)


class MCPTokenAuthentication(BaseAuthentication):
    """
    Simple token-based authentication for MCP contexts.
    
    Validates bearer tokens and binds them to Django User objects.
    In production, integrate with django-oauth-toolkit or similar.
    """

    keyword = "Bearer"
    model = None

    def get_model(self):
        """Get the User model"""
        if self.model is not None:
            return self.model
        from django.contrib.auth.models import User

        return User

    def authenticate(self, request):
        """
        Authenticate request using bearer token.
        
        Args:
            request: DRF Request object
            
        Returns:
            (user, auth) tuple or None if no authentication provided
            
        Raises:
            AuthenticationFailed: If token is invalid
        """
        auth = self._get_authorization_header(request)

        if not auth:
            return None

        if isinstance(auth, bytes):
            auth = auth.decode("utf-8")

        auth_parts = auth.split()

        if len(auth_parts) != 2 or auth_parts[0].lower() != self.keyword.lower():
            return None

        token = auth_parts[1]

        try:
            # In a real implementation, validate the token against OAuth2 server
            # or JWT claims. For now, this is a placeholder.
            user = self._authenticate_token(token)
            return (user, token)
        except AuthenticationFailed as e:
            raise e
        except Exception as e:
            logger.error(f"Token authentication error: {e}")
            raise AuthenticationFailed("Invalid authentication credentials.") from e

    def _authenticate_token(self, token: str) -> User:
        """
        Authenticate a token and return associated user.
        
        Args:
            token: Bearer token string
            
        Returns:
            Django User object
            
        Raises:
            AuthenticationFailed: If token is invalid or user not found
        """
        # TODO: Implement actual OAuth2 token validation
        # For now, reject all tokens (MCP context should handle auth)
        raise AuthenticationFailed("Token authentication not configured.")

    @staticmethod
    def _get_authorization_header(request) -> Optional[str]:
        """
        Extract Authorization header from request.
        
        Args:
            request: DRF Request object
            
        Returns:
            Authorization header value or None
        """
        auth_header = request.META.get("HTTP_AUTHORIZATION", "")
        return auth_header if auth_header else None


class MCPContextUser:
    """
    Wrapper for MCP context user information.
    
    Allows MCP context user data to be treated as Django User object
    in DRF permission checks.
    """

    def __init__(self, context_user: Optional[Any] = None):
        """
        Initialize MCP context user wrapper.
        
        Args:
            context_user: User object from FastMCP context
        """
        self.context_user = context_user
        self.username = getattr(context_user, "username", "mcp-agent")
        self.email = getattr(context_user, "email", "agent@mcp.local")
        self.id = getattr(context_user, "id", None)
        self.is_authenticated = True
        self.is_active = True
        self.is_staff = False
        self.is_superuser = False

    def has_perm(self, perm: str, obj: Optional[Any] = None) -> bool:
        """
        Check if user has permission.
        
        Args:
            perm: Permission string
            obj: Optional object for object-level checks
            
        Returns:
            Permission result (delegates to context_user if available)
        """
        if self.context_user and hasattr(self.context_user, "has_perm"):
            return self.context_user.has_perm(perm, obj)
        return False

    def has_module_perms(self, app_label: str) -> bool:
        """Check if user has module-level permissions."""
        if self.context_user and hasattr(self.context_user, "has_module_perms"):
            return self.context_user.has_module_perms(app_label)
        return False


class PermissionChecker:
    """
    Helper for enforcing DRF permission checks in MCP context.
    
    Ensures that MCP tool invocations respect DRF's permission system.
    """

    @staticmethod
    def check_view_permission(view, request) -> bool:
        """
        Check view-level permissions.
        
        Args:
            view: DRF view instance
            request: DRF Request object
            
        Returns:
            True if permission granted
            
        Raises:
            PermissionDenied: If permission check fails
        """
        if hasattr(view, "check_permissions"):
            view.check_permissions(request)
        return True

    @staticmethod
    def check_object_permission(view, request, obj) -> bool:
        """
        Check object-level permissions.
        
        Args:
            view: DRF view instance
            request: DRF Request object
            obj: Object to check permissions against
            
        Returns:
            True if permission granted
            
        Raises:
            PermissionDenied: If permission check fails
        """
        if hasattr(view, "check_object_permissions"):
            view.check_object_permissions(request, obj)
        return True
