"""Authorization decorators for role and permission gating.

Authentication (is the caller logged in?) is handled by Flask-JWT-Extended's
@jwt_required. Authorization (is the caller ALLOWED to do this?) is handled
here. The two are separate concerns; a route needs both on any state-changing
action.

These decorators call verify_jwt_in_request() themselves, so they work whether
or not a separate @jwt_required is also present. The admin role bypasses every
permission check (see User.haspermission), so an admin never needs individual
permissions granted.

Usage:

    @assets_bp.route('/<int:asset_id>', methods=['DELETE'])
    @jwt_required()
    @require_permission('assets.delete')
    def delete_asset(asset_id):
        ...
"""

from functools import wraps

from flask_jwt_extended import verify_jwt_in_request, current_user

from shopdb.utils.responses import error_response, ErrorCodes


def require_permission(permission_name: str):
    """Gate a route behind a single permission. Admin role bypasses."""
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(*args, **kwargs):
            # verify jwt first so current_user is loaded (idempotent if the
            # route also has @jwt_required)
            verify_jwt_in_request()
            if current_user is None:
                return error_response(
                    ErrorCodes.UNAUTHORIZED,
                    'Authentication required',
                    http_code=401
                )
            if not current_user.haspermission(permission_name):
                return error_response(
                    ErrorCodes.FORBIDDEN,
                    'You do not have permission to perform this action',
                    http_code=403
                )
            return view_func(*args, **kwargs)
        return wrapper
    return decorator


def require_role(rolename: str):
    """Gate a route behind a single role (e.g. 'admin')."""
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(*args, **kwargs):
            verify_jwt_in_request()
            if current_user is None:
                return error_response(
                    ErrorCodes.UNAUTHORIZED,
                    'Authentication required',
                    http_code=401
                )
            if not current_user.hasrole(rolename):
                return error_response(
                    ErrorCodes.FORBIDDEN,
                    f'{rolename.capitalize()} access required',
                    http_code=403
                )
            return view_func(*args, **kwargs)
        return wrapper
    return decorator
