"""
FastAPI Dependencies für Authentifizierung und Autorisierung

OWASP A01: Broken Access Control Mitigation
"""
from typing import Optional
from fastapi import Depends, HTTPException, status, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from app.database import get_db
from app.models.user import User, UserRole
from app.auth.jwt_handler import decode_token
from app.auth.token_revocation import is_revoked

# Security Scheme für Swagger UI
security = HTTPBearer(auto_error=False)


async def get_current_user(
    request: Request,
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db)
) -> User:
    """
    Extrahiert und validiert aktuellen User aus JWT-Token

    Args:
        credentials: HTTP Bearer Token
        db: Database Session

    Returns:
        User-Objekt

    Raises:
        HTTPException 401: Bei ungültigem Token oder nicht existierendem User
    """
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Invalid authentication",
        headers={"WWW-Authenticate": "Bearer"},
    )

    # Decodiere Token (Authorization header bevorzugt)
    token = None
    if credentials:
        token = credentials.credentials
    if not token:
        token = request.cookies.get("access_token")

    if not token:
        raise credentials_exception
    payload = decode_token(token)

    if payload is None:
        raise credentials_exception

    jti = payload.get("jti")
    if jti and is_revoked(jti):
        raise credentials_exception

    username: str = payload.get("sub")
    if username is None:
        raise credentials_exception

    # Hole User aus DB
    user = db.query(User).filter(User.username == username).first()

    if user is None:
        raise credentials_exception

    # Prüfe ob User aktiv
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User account is deactivated"
        )

    return user


async def get_current_active_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """
    Alias für get_current_user (für Klarheit im Code)

    Usage:
        @app.get("/protected")
        def protected_route(user: User = Depends(get_current_active_user)):
            return {"user": user.username}
    """
    return current_user


class PermissionChecker:
    """
    Dependency für Rollen-basierte Zugriffskontrolle (RBAC)

    Usage:
        # Nur Admins
        @app.delete("/users/{id}")
        def delete_user(
            id: int,
            user: User = Depends(PermissionChecker(UserRole.ADMIN))
        ):
            ...

        # Admins und Editors
        @app.patch("/vulnerabilities/{id}")
        def patch_vuln(
            id: int,
            user: User = Depends(PermissionChecker(UserRole.EDITOR))
        ):
            ...
    """

    def __init__(self, required_role: UserRole):
        """
        Args:
            required_role: Mindestens erforderliche Rolle
        """
        self.required_role = required_role

    def __call__(self, current_user: User = Depends(get_current_user)) -> User:
        """
        Prüft Berechtigung des Users

        Args:
            current_user: Aktueller User

        Returns:
            User-Objekt wenn berechtigt

        Raises:
            HTTPException 403: Bei fehlender Berechtigung
        """
        if not current_user.has_permission(self.required_role):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Access denied. Required role: {self.required_role.value}"
            )

        return current_user


# Convenience Aliases
RequireAdmin = PermissionChecker(UserRole.ADMIN)
RequireEditor = PermissionChecker(UserRole.EDITOR)
RequireReadonly = PermissionChecker(UserRole.READONLY)
