from collections.abc import Iterable

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session

from app.core.security import verify_access_token
from app.db.database import get_db
from app.models.user import User
from app.repositories.user_repository import UserRepository

bearer_scheme = HTTPBearer(auto_error=False)


def get_current_user(
    credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
    db: Session = Depends(get_db),
) -> User:
    if credentials is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Nicht authentifiziert",
            headers={"WWW-Authenticate": "Bearer"},
        )

    username = verify_access_token(credentials.credentials)
    user = UserRepository.get_by_username(db, username)

    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Nicht authentifiziert",
            headers={"WWW-Authenticate": "Bearer"},
        )

    return user


def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
    if not current_user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Nicht authentifiziert",
            headers={"WWW-Authenticate": "Bearer"},
        )

    return current_user


def get_user_permission_names(user: User) -> set[str]:
    if user.primary_role is None:
        return set()

    return {permission.name for permission in user.primary_role.permissions}


def require_permission(permission: str):
    def dependency(current_user: User = Depends(get_current_active_user)) -> User:
        if permission not in get_user_permission_names(current_user):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Keine Berechtigung",
            )
        return current_user

    return dependency


def require_any_permission(permissions: Iterable[str]):
    permission_set = set(permissions)

    def dependency(current_user: User = Depends(get_current_active_user)) -> User:
        if get_user_permission_names(current_user).isdisjoint(permission_set):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Keine Berechtigung",
            )
        return current_user

    return dependency


def require_all_permissions(permissions: Iterable[str]):
    permission_set = set(permissions)

    def dependency(current_user: User = Depends(get_current_active_user)) -> User:
        if not permission_set.issubset(get_user_permission_names(current_user)):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Keine Berechtigung",
            )
        return current_user

    return dependency
