from typing import Self, overload

from pyidentity.exc import ArgumentNullError, InvalidOperationError
from pyidentity.security.authorization.options import AuthorizationOptions
from pyidentity.security.authorization.policy import AuthorizationPolicy
from pyidentity.security.authorization.policy_builder import AuthorizationPolicyBuilder
from pyidentity.security.authorization.types import ConfigurePolicy

__all__ = ("AuthorizationBuilder",)


class AuthorizationBuilder:
    """Used to configure authorization."""

    __slots__ = ("options",)

    def __init__(self, options: AuthorizationOptions) -> None:
        self.options = options

    @overload
    def add_policy(self, name: str, policy: AuthorizationPolicy, /) -> Self: ...

    @overload
    def add_policy(self, name: str, configure_builder: ConfigurePolicy, /) -> Self: ...

    def add_policy(
        self,
        name: str,
        policy_or_configure_builder: AuthorizationPolicy | ConfigurePolicy,
        /,
    ) -> Self:
        """Add an authorization policy with the provided name or built from a delegate with the provided name.

        :param name: The name of the policy.
        :param policy_or_configure_builder: The authorization policy or delegate that will be used to build the policy.
        :return:
        """
        self.options.add_policy(name, policy_or_configure_builder)
        return self

    @overload
    def set_default_policy(self, policy: AuthorizationPolicy, /) -> Self: ...

    @overload
    def set_default_policy(self, configure_builder: ConfigurePolicy, /) -> Self: ...

    def set_default_policy(self, policy_or_configure_builder: AuthorizationPolicy | ConfigurePolicy, /) -> Self:
        """Sets the default authorization policy. Defaults to require authenticated users.

        :param policy_or_configure_builder: The authorization policy or delegate that will be used to build the policy.
        :return:
        """
        if policy_or_configure_builder is None:
            raise ArgumentNullError("policy_or_configure_builder")
        if isinstance(policy_or_configure_builder, AuthorizationPolicy):
            policy = policy_or_configure_builder
        elif callable(policy_or_configure_builder):
            builder = AuthorizationPolicyBuilder()
            policy_or_configure_builder(builder)
            policy = builder.build()
        else:
            raise InvalidOperationError("Unsupported function arguments.")

        self.options.default_policy = policy
        return self
