name = "eduperson"

import logging

import regex

logger = logging.getLogger(__name__)


class Entitlement:
    """EduPerson Entitlement attribute (de-)serialisation.

    As specified in: https://aarc-project.eu/guidelines/aarc-g002/
    """

    # This regex is not compatible with stdlib 're', we need 'regex'!
    # (because of repeated captures, see https://bugs.python.org/issue7132)
    re = regex.compile(
        r"urn:"
        + r"(?P<nid>[^:]+):(?P<delegated_namespace>[^:]+)"  # Namespace-ID and delegated URN namespace
        + r"(:(?P<subnamespace>[^:]+))*?"  # Sub-namespaces
        + r":group:"
        + r"(?P<group>[^:]+)"  # Root group
        + r"(:(?P<subgroup>[^:]+))*?"  # Sub-groups
        + r"(:role=(?P<role>.+))?"  # Role of the user in the deepest group
        + r"#(?P<group_authority>.+)"  # Authoritative soruce of the entitlement (URN)
    )

    def __init__(self, raw):
        """Parse a raw EduPerson entitlement string in the AARC-G002 format."""
        match = self.re.fullmatch(raw)

        if not match:
            raise ValueError("Invalid entitlement attribute")

        [self.namespace_id] = match.captures("nid")
        [self.delegated_namespace] = match.captures("delegated_namespace")

        self.subnamespaces = match.captures("subnamespace")

        [self.group] = match.captures("group")
        self.subgroups = match.captures("subgroup")
        [self.role] = match.captures("role") or [None]

        [self.group_authority] = match.captures("group_authority")

    def __repr__(self):
        """Serialize the entitlement to the AARC-G002 format.

        This is the inverse to `__init__` and thus `ent_str == repr(Entitlement(ent_str))`
        holds for any valid entitlement.
        """
        return (
            "urn:{namespace_id}:{delegated_namespace}{subnamespaces}"
            + ":group:{group}{subgroups}{role}"
            + "#{group_authority}"
        ).format(
            **{
                **self.__dict__,
                **{
                    "subnamespaces": "".join(
                        [":{}".format(ns) for ns in self.subnamespaces]
                    ),
                    "subgroups": "".join([":{}".format(grp) for grp in self.subgroups]),
                    "role": ":role={}".format(self.role) if self.role else "",
                },
            }
        )

    def __str__(self):
        """Return the entitlement in human-readable string form."""
        return (
            "<Entitlement"
            + " namespace={namespace_id}:{delegated_namespace}{subnamespaces}"
            + " group={group}{subgroups}"
            + "{role}"
            + " auth={group_authority}>"
        ).format(
            **{
                **self.__dict__,
                **{
                    "subnamespaces": "".join(
                        [",{}".format(ns) for ns in self.subnamespaces]
                    ),
                    "subgroups": "".join([",{}".format(grp) for grp in self.subgroups]),
                    "role": " role={}".format(self.role) if self.role else "",
                },
            }
        )

    @property
    def all_toplevel_groups(self):
        return ["_".join([self.group])]

    @property
    def all_groups(self):
        return ["_".join([self.group] + self.subgroups)]

    @property
    def full_namespace(self):
        return [self.delegated_namespace] + self.subnamespaces
