"""
JWT WebSocket Authentication Middleware.

Reads a JWT access token from the WebSocket query string (?token=<jwt>)
and authenticates the user, populating scope["user"].

Usage in asgi.py:
    from apps.core.auth.ws_middleware import JwtAuthMiddlewareStack
    ...
    'websocket': JwtAuthMiddlewareStack(URLRouter(websocket_urlpatterns))
"""
import logging
from urllib.parse import parse_qs

from channels.auth import AuthMiddlewareStack
from channels.db import database_sync_to_async
from channels.middleware import BaseMiddleware
from django.contrib.auth.models import AnonymousUser

logger = logging.getLogger('apps')


@database_sync_to_async
def get_user_from_token(token_key: str):
    """Validate JWT and return User or AnonymousUser."""
    try:
        from rest_framework_simplejwt.tokens import AccessToken
        from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
        from apps.core.auth.models import User

        token = AccessToken(token_key)
        user_id = token.get('user_id')
        if user_id is None:
            return AnonymousUser()

        user = User.objects.select_related('tenant').get(pk=user_id)
        if not user.is_active:
            return AnonymousUser()
        return user
    except Exception as exc:
        logger.debug(f"[WsJwtAuth] Token validation failed: {exc}")
        return AnonymousUser()


class JwtAuthMiddleware(BaseMiddleware):
    """
    Middleware that reads ?token=<jwt> from the WebSocket URL
    and populates scope["user"].
    Falls back to AnonymousUser if token is absent or invalid.
    """

    async def __call__(self, scope, receive, send):
        # Extract token from query string
        query_string = scope.get('query_string', b'').decode()
        params = parse_qs(query_string)
        token_list = params.get('token', [])

        if token_list:
            scope['user'] = await get_user_from_token(token_list[0])
        else:
            # No token provided — leave as AnonymousUser
            scope.setdefault('user', AnonymousUser())

        return await super().__call__(scope, receive, send)


def JwtAuthMiddlewareStack(inner):
    """
    Wraps JwtAuthMiddleware around the inner ASGI app.
    Keeps Django's AuthMiddlewareStack for HTTP/session compatibility.
    """
    return JwtAuthMiddleware(AuthMiddlewareStack(inner))
