"""
Permission Contract

Standard permission definitions and role contracts.
"""

from dataclasses import dataclass
from typing import List, Set, Optional
from enum import Enum


class PermissionAction(str, Enum):
    """Standard permission actions."""
    
    VIEW = "view"
    CREATE = "create"
    UPDATE = "update"
    DELETE = "delete"
    MANAGE = "manage"  # Full access
    EXPORT = "export"
    IMPORT = "import"
    EXECUTE = "execute"


@dataclass
class Permission:
    """
    Permission definition.
    
    Format: {resource}:{action}
    Example: user:view, table:manage
    """
    
    resource: str
    action: PermissionAction
    
    @property
    def code(self) -> str:
        """Return permission code."""
        return f"{self.resource}:{self.action.value}"
    
    def __str__(self) -> str:
        return self.code
    
    def __hash__(self) -> int:
        return hash(self.code)
    
    def __eq__(self, other) -> bool:
        if isinstance(other, Permission):
            return self.code == other.code
        if isinstance(other, str):
            return self.code == other
        return False


@dataclass
class Role:
    """
    Role definition with associated permissions.
    """
    
    code: str
    name: str
    description: Optional[str] = None
    permissions: Set[str] = None
    is_system: bool = False  # System roles cannot be modified
    
    def __post_init__(self):
        if self.permissions is None:
            self.permissions = set()
    
    def has_permission(self, permission: str) -> bool:
        """Check if role has a specific permission."""
        # Wildcard permission
        if "*" in self.permissions:
            return True
        
        # Exact match
        if permission in self.permissions:
            return True
        
        # Resource-level wildcard (e.g., "user:*" matches "user:view")
        resource = permission.split(":")[0]
        if f"{resource}:*" in self.permissions:
            return True
        
        return False
    
    def add_permission(self, permission: str) -> None:
        """Add a permission to the role."""
        if self.is_system:
            raise ValueError("Cannot modify system roles")
        self.permissions.add(permission)
    
    def remove_permission(self, permission: str) -> None:
        """Remove a permission from the role."""
        if self.is_system:
            raise ValueError("Cannot modify system roles")
        self.permissions.discard(permission)


@dataclass
class PermissionContext:
    """
    Context for permission checks.
    
    Contains information about the user, tenant, and resource
    being accessed.
    """
    
    user_id: str
    tenant_id: str
    roles: List[str]
    permissions: Set[str]
    resource_owner_id: Optional[str] = None
    
    def has_permission(self, permission: str) -> bool:
        """Check if context has a specific permission."""
        return permission in self.permissions or "*" in self.permissions
    
    def is_owner(self) -> bool:
        """Check if user is the resource owner."""
        return self.resource_owner_id == self.user_id
    
    def can_access(self, permission: str, allow_owner: bool = False) -> bool:
        """
        Check if user can perform action.
        
        Args:
            permission: Required permission
            allow_owner: Allow access if user is owner
            
        Returns:
            True if access is allowed
        """
        if self.has_permission(permission):
            return True
        
        if allow_owner and self.is_owner():
            return True
        
        return False
