"""Auth plumbing for the JSON API: body parsing, errors, JWT+portal-role guard.

`jwt_required` replaces the old ApiToken-based `api_login_required` decorator.
It reads the user/claims DRF's YatraJWTAuthentication already resolved onto
the request, then exposes them as `request.api_user` / `request.api_token`
so every existing view in views_operator.py / views_admin.py keeps working
completely unchanged.
"""
from functools import wraps

from django.http import JsonResponse

from testing_app.models import AdminAudit


def body(request):
    """The parsed request body. Works for DRF Request (JSON or multipart)
    and, as a fallback, plain Django HttpRequest."""
    if hasattr(request, 'data'):
        return request.data
    import json
    try:
        return json.loads(request.body.decode('utf-8') or '{}')
    except (ValueError, UnicodeDecodeError):
        return {}


def err(message, status=400, **extra):
    return JsonResponse({'ok': False, 'error': message, **extra}, status=status)


def ok(payload=None, **extra):
    data = {'ok': True}
    if payload is not None:
        data['data'] = payload
    data.update(extra)
    return JsonResponse(data)


def jwt_required(*roles):
    """Guard an @api_view: valid JWT + (optionally) a specific portal role."""
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            user = getattr(request, 'user', None)
            token = getattr(request, 'auth', None)
            if not user or not getattr(user, 'id', None) or token is None:
                return err('Authentication required. Please login again.', status=401)
            if roles and token.get('role') not in roles:
                return err(f'This action needs {" / ".join(roles)} access.', status=403)
            request.api_user = user
            request.api_token = token
            return view_func(request, *args, **kwargs)
        return wrapper
    return decorator


def api_audit(request, action, target, reason_code=None, note=None):
    """Audit-log an admin API action against the token's user."""
    AdminAudit.objects.create(
        admin=getattr(request, 'api_user', None),
        action=action, target=target,
        reason_code=reason_code, note=note,
    )
