from collections.abc import Iterable

from pyidentity import resources
from pyidentity.exc import ArgumentNullError, InvalidOperationError
from pyidentity.security.authorization.abc import IAuthorizationHandler

__all__ = ("AuthorizationPolicy",)


class AuthorizationPolicy:
    """Represents a collection of authorization requirements evaluated against,
    all of which must succeed for authorization to succeed.
    """

    __slots__ = ("_requirements", "_schemes")

    def __init__(
        self,
        requirements: Iterable[IAuthorizationHandler],
        authentication_schemes: Iterable[str],
    ) -> None:
        if requirements is None:
            raise ArgumentNullError("requirements")
        if authentication_schemes is None:
            raise ArgumentNullError("authentication_schemes")
        if not requirements:
            raise InvalidOperationError(resources.AuthorizationPolicyEmpty)

        self._schemes = frozenset(authentication_schemes)
        self._requirements = frozenset(requirements)

    @property
    def schemes(self) -> frozenset[str]:
        """Gets frozenset of the authentication schemes the *requirements* are evaluated against."""
        return self._schemes

    @property
    def requirements(self) -> frozenset[IAuthorizationHandler]:
        """Gets a frozenset of *IAuthorizationHandlers* which must succeed for this policy to be successful."""
        return self._requirements

    def combine(self, policies: Iterable["AuthorizationPolicy"]) -> "AuthorizationPolicy":
        """Combines the specified *AuthorizationPolicy* into a single policy.

        :param policies: The authorization policies to combine.
        :return: A new *AuthorizationPolicy* which represents the combination of the specified policies.
        """
        requirements = list(self._requirements)
        schemes = list(self._schemes)
        for policy in policies:
            requirements.extend(policy.requirements)
            schemes.extend(policy.schemes)
        return self.__class__(requirements, schemes)
