"""Permission model with wildcard-aware matching.

Permissions use the format 'resource_type:action'. Resource identification
(specific IDs, instances) is handled by the Resource model, not the permission
string. For namespaced actions, use the resource_type segment: 'admin_users:ban'.
"""

from pydantic import BaseModel, model_validator


class Permission(BaseModel):
    """A permission representing an action on a resource type.

    Supports wildcards: 'users:*', '*:read', '*:*', 'documents:read'.

    Example:
        perm = Permission.from_string("documents:read")
        perm.matches("documents", "read")   # True
        perm.matches("documents", "write")  # False

        wildcard = Permission.from_string("*:*")
        wildcard.matches("anything", "anything")  # True
    """

    resource_type: str
    action: str

    @model_validator(mode="after")
    def _validate_non_empty(self) -> "Permission":
        if not self.resource_type:
            raise ValueError("resource_type must not be empty")
        if not self.action:
            raise ValueError("action must not be empty")
        return self

    @classmethod
    def from_string(cls, s: str) -> "Permission":
        """Parse 'resource_type:action' format.

        Args:
            s: A permission string like 'documents:read' or '*:*'.

        Returns:
            A Permission instance.

        Raises:
            ValueError: If the string doesn't contain exactly one colon separator.
        """
        if ":" not in s:
            raise ValueError(f"Permission must be 'resource_type:action', got '{s}'")
        resource_type, action = s.split(":", 1)
        return cls(resource_type=resource_type, action=action)

    def matches(self, resource_type: str, action: str) -> bool:
        """Check if this permission matches a given resource type and action.

        Wildcards ('*') match any value in their position.

        Args:
            resource_type: The resource type to check against.
            action: The action to check against.

        Returns:
            True if this permission matches the given resource type and action.
        """
        r_match = self.resource_type == "*" or self.resource_type == resource_type
        a_match = self.action == "*" or self.action == action
        return r_match and a_match

    def __str__(self) -> str:
        return f"{self.resource_type}:{self.action}"

    def __hash__(self) -> int:
        return hash((self.resource_type, self.action))

    def __eq__(self, other: object) -> bool:
        if isinstance(other, Permission):
            return self.resource_type == other.resource_type and self.action == other.action
        return NotImplemented
