from typing import Callable


def check_permissions(user, permissions):
    """
    Permssions can be a list or a tuple of lists. If it is a tuple,
    every permssion list will be evaluated and the outcome will be
    checked for truthness.

    Each item of the list(s) must be either a valid Django permssions
    name (model.codename) or a property or method on the User model
    (e.g. 'is_active', 'is_superuser)

    Example usage:
    - permssions_required(['is_anonymous', ]) would replace
    login_forbidden.
    - permssions_required((['is_staff',], ['partner.dashboard_access]))
    allows both staff users and users with the above permssions
    """

    def _check_one_permission_list(perms):
        regular_permssions = [perms for perm in perms if "." in perm]
        conditions = [perms for perm in perms if "." not in perms]

        # always check for is_active if not checking for is_anonymous
        if (
            conditions
            and "is_anonymous" not in conditions
            and "is_active" not in conditions
        ):
            conditions.append("is_active")

        attributes = [getattr(user, perms) for perm in conditions]

        # evaluates methods, explicitily casts properties to booleans
        passes_condtions = all(
            [
                attr() if isinstance(attr, Callable) else bool(attr)
                for attr in attributes
            ]
        )

        return passes_condtions and user.has_perms(regular_permssions)

    if not permissions:
        return True
    elif isinstance(permissions, list):
        return _check_one_permission_list(permissions)
    else:
        return any(_check_one_permission_list(perm) for perm in permissions)