"""
MCP-Authentifizierung – Token-basierte Authentifizierung mit 3 Rollen.

Tokens werden über Umgebungsvariablen konfiguriert:
  MCP_TOKEN_READONLY  – Nur-Lese-Zugriff (alle Daten, PII maskiert)
  MCP_TOKEN_EDITOR    – Lesen + Schreiben (PII maskiert)
  MCP_TOKEN_ADMIN     – Voll-Zugriff (keine PII-Maskierung, alle Schreib-Ops)

Das aktive Token wird per MCP_AUTH_TOKEN übergeben (wird vom MCP-Client gesetzt).
"""

import os

ROLE_READONLY = "readonly"
ROLE_EDITOR = "editor"
ROLE_ADMIN = "admin"

# Rollenrangfolge (höher = mehr Rechte)
ROLE_RANK = {ROLE_READONLY: 1, ROLE_EDITOR: 2, ROLE_ADMIN: 3}


def _token_map() -> dict[str, str]:
    """Erstellt Mapping token → Rolle aus Umgebungsvariablen."""
    mapping: dict[str, str] = {}
    for role, env_var in [
        (ROLE_READONLY, "MCP_TOKEN_READONLY"),
        (ROLE_EDITOR, "MCP_TOKEN_EDITOR"),
        (ROLE_ADMIN, "MCP_TOKEN_ADMIN"),
    ]:
        token = os.environ.get(env_var, "").strip()
        if token:
            mapping[token] = role
    return mapping


def get_role_for_token(token: str) -> str | None:
    """
    Gibt die Rolle für einen Token zurück oder None bei ungültigem Token.
    """
    if not token:
        return None
    return _token_map().get(token)


def get_current_role() -> str | None:
    """
    Gibt die Rolle des aktuell gesetzten MCP_AUTH_TOKEN zurück.
    Wird vom Server beim Start einmalig ausgewertet.
    """
    token = os.environ.get("MCP_AUTH_TOKEN", "").strip()
    return get_role_for_token(token)


def can_write(role: str | None) -> bool:
    """Darf die Rolle Schreiboperationen ausführen?"""
    return role in (ROLE_EDITOR, ROLE_ADMIN)


def can_read_unmasked(role: str | None) -> bool:
    """Darf die Rolle ungemaskierte PII-Daten lesen?"""
    return role == ROLE_ADMIN


def require_role(role: str | None) -> None:
    """Wirft ValueError wenn keine gültige Rolle vorhanden."""
    if not role:
        raise ValueError(
            "Ungültiger oder fehlender MCP_AUTH_TOKEN. "
            "Bitte MCP_AUTH_TOKEN-Umgebungsvariable setzen."
        )
