import functools

from quart import g, jsonify, request, session

from scribe.services.auth import get_user_by_id
from scribe.services.api_keys import lookup_key


def _check_auth(f, required_role: str | None = None):
    @functools.wraps(f)
    async def decorated(*args, **kwargs):
        # --- Bearer token path ---
        auth_header = request.headers.get("Authorization", "")
        if auth_header.startswith("Bearer "):
            raw_key = auth_header[len("Bearer "):]
            api_key = await lookup_key(raw_key)
            if api_key is None:
                return jsonify({"error": "Invalid or revoked API key"}), 401
            user = await get_user_by_id(api_key.user_id)
            if not user:
                return jsonify({"error": "User not found"}), 401
            # Scope enforcement: read-only keys cannot mutate
            if api_key.scope == "read" and request.method not in ("GET", "HEAD", "OPTIONS"):
                return jsonify({"error": "Read-only key cannot perform write operations"}), 403
            # Role check (admin_required routes)
            if required_role and user.role != required_role:
                return jsonify({"error": "Admin access required"}), 403
            g.user = user
            g.api_key = api_key
            return await f(*args, **kwargs)

        # --- Session path (unchanged) ---
        user_id = session.get("user_id")
        if not user_id:
            return jsonify({"error": "Authentication required"}), 401
        user = await get_user_by_id(user_id)
        if not user:
            session.clear()
            return jsonify({"error": "Authentication required"}), 401
        if session.get("session_version") != user.session_version:
            session.clear()
            return jsonify({"error": "Session expired. Please log in again."}), 401
        if required_role and user.role != required_role:
            return jsonify({"error": "Admin access required"}), 403
        g.user = user
        return await f(*args, **kwargs)
    return decorated


def login_required(f):
    return _check_auth(f)


def admin_required(f):
    return _check_auth(f, required_role="admin")


def get_current_user_id() -> int:
    return g.user.id
