"""Permission matching with wildcard support for namespaced permissions.

This module provides functions for matching permissions using a namespace.resource:action
format with optional wildcards. The permission model follows these rules:

Permission format: namespace.resource:action

Examples:
  - fishinfo.telemetry:read
  - vikdata.users:write
  - ingress.cores:delete

Wildcard support:
  - *:* - matches everything (legacy superadmin)
  - *.*:* - matches everything (explicit superadmin)
  - fishinfo.*:* - matches all fishinfo permissions
  - fishinfo.telemetry:* - matches all telemetry actions
  - *.telemetry:read - matches telemetry:read in any namespace
  - *.*:read - matches read action on any resource
"""


def parse_permission(permission: str) -> tuple[str | None, str, str]:
    """Parse a permission string into (namespace, resource, action).

    Args:
        permission: Permission string like "fishinfo.telemetry:read" or "users:read"

    Returns:
        Tuple of (namespace, resource, action).
        Namespace is None for legacy format like "users:read".

    Examples:
        >>> parse_permission("fishinfo.telemetry:read")
        ("fishinfo", "telemetry", "read")
        >>> parse_permission("users:read")
        (None, "users", "read")
        >>> parse_permission("*:*")
        (None, "*", "*")
        >>> parse_permission("*.*:*")
        ("*", "*", "*")
    """
    if ":" not in permission:
        # No action specified, treat whole thing as resource with wildcard action
        return None, permission, "*"

    # Split by last colon to get resource_part and action
    resource_part, action = permission.rsplit(":", 1)

    if "." in resource_part:
        # Has namespace: namespace.resource
        namespace, resource = resource_part.split(".", 1)
        return namespace, resource, action

    # Legacy format: resource:action (no namespace)
    return None, resource_part, action


def match_permission(user_permission: str, required: str) -> bool:
    """Check if a user permission matches a required permission.

    Supports namespaced permissions (namespace.resource:action) and wildcards:
    - "*:*" matches everything (legacy superadmin)
    - "*.*:*" matches everything (explicit superadmin)
    - "fishinfo.*:*" matches all fishinfo permissions
    - "fishinfo.telemetry:*" matches all telemetry actions
    - "fishinfo.telemetry:read" matches exact permission

    Args:
        user_permission: Permission the user has
        required: Permission that is required

    Returns:
        True if user_permission grants the required permission

    Examples:
        >>> match_permission("fishinfo.telemetry:*", "fishinfo.telemetry:read")
        True
        >>> match_permission("fishinfo.*:*", "fishinfo.zones:write")
        True
        >>> match_permission("*:*", "anything.here:now")
        True
        >>> match_permission("*.*:*", "fishinfo.telemetry:read")
        True
        >>> match_permission("vikdata.users:read", "fishinfo.telemetry:read")
        False
    """
    # Legacy superadmin wildcard - matches everything
    if user_permission == "*:*":
        return True

    # New explicit superadmin wildcard - matches everything
    if user_permission == "*.*:*":
        return True

    # Exact match
    if user_permission == required:
        return True

    # Parse both permissions
    user_ns, user_res, user_act = parse_permission(user_permission)
    req_ns, req_res, req_act = parse_permission(required)

    # Namespace matching
    # - If user has no namespace (legacy), it only matches required with no namespace
    # - If user namespace is "*", it matches any namespace
    # - Otherwise, namespaces must match exactly
    if user_ns is None and req_ns is not None:
        # Legacy permission cannot match namespaced requirement
        return False
    if user_ns is not None and req_ns is None:
        # Namespaced permission cannot match legacy requirement
        # (unless it's a wildcard namespace)
        if user_ns != "*":
            return False
    if user_ns is not None and req_ns is not None:
        # Both have namespaces - must match or user is wildcard
        if user_ns != "*" and user_ns != req_ns:
            return False

    # Resource matching
    if user_res != "*" and user_res != req_res:
        return False

    # Action matching
    if user_act != "*" and user_act != req_act:
        return False

    return True


def has_permission(user_permissions: list[str], required: str) -> bool:
    """Check if any user permission matches the required permission.

    Args:
        user_permissions: List of permissions the user has
        required: Permission that is required

    Returns:
        True if any user permission grants the required permission

    Examples:
        >>> has_permission(["fishinfo.telemetry:read"], "fishinfo.telemetry:read")
        True
        >>> has_permission(["fishinfo.*:*"], "fishinfo.zones:write")
        True
        >>> has_permission(["vikdata.users:read"], "fishinfo.telemetry:read")
        False
        >>> has_permission(["*:*"], "anything.here:now")
        True
    """
    return any(match_permission(p, required) for p in user_permissions)


def has_any_permission(user_permissions: list[str], required: list[str]) -> bool:
    """Check if user has any of the required permissions.

    Args:
        user_permissions: List of permissions the user has
        required: List of permissions where at least one is required

    Returns:
        True if user has at least one of the required permissions

    Examples:
        >>> has_any_permission(["fishinfo.telemetry:read"], ["fishinfo.telemetry:read", "fishinfo.zones:write"])
        True
        >>> has_any_permission(["vikdata.users:read"], ["fishinfo.telemetry:read", "fishinfo.zones:write"])
        False
    """
    return any(has_permission(user_permissions, r) for r in required)


def has_all_permissions(user_permissions: list[str], required: list[str]) -> bool:
    """Check if user has all of the required permissions.

    Args:
        user_permissions: List of permissions the user has
        required: List of permissions that are all required

    Returns:
        True if user has all of the required permissions

    Examples:
        >>> has_all_permissions(["fishinfo.telemetry:read", "fishinfo.zones:write"], ["fishinfo.telemetry:read", "fishinfo.zones:write"])
        True
        >>> has_all_permissions(["fishinfo.telemetry:read"], ["fishinfo.telemetry:read", "fishinfo.zones:write"])
        False
        >>> has_all_permissions(["fishinfo.*:*"], ["fishinfo.telemetry:read", "fishinfo.zones:write"])
        True
    """
    return all(has_permission(user_permissions, r) for r in required)


def is_superadmin(user_permissions: list[str]) -> bool:
    """Check if user has superadmin privileges.

    Superadmin is recognized by either:
    - "*:*" (legacy format)
    - "*.*:*" (new explicit format)

    Args:
        user_permissions: List of permissions the user has

    Returns:
        True if user has superadmin permission
    """
    return "*:*" in user_permissions or "*.*:*" in user_permissions
