"""Type definitions for the RBAC permission system."""

from dataclasses import dataclass
from typing import Literal, Tuple, Callable, Awaitable, TypeAlias, Union, List, Dict, Optional, TYPE_CHECKING
from enum import Enum

if TYPE_CHECKING:
    from fastapi import Request
    from .service import RBACService


class PermissionOperator(str, Enum):
    """Operator for combining multiple permissions."""
    AND = "AND"
    OR = "OR"


@dataclass
class CheckResult:
    """
    Result from pre-check or post-check callbacks.

    Attributes:
        allowed: Whether access is granted (True), denied (False), or should continue (None for pre-check)
        message: Optional custom error message when denied

    Examples:
        # Grant access immediately
        CheckResult(allowed=True)

        # Deny with default message
        CheckResult(allowed=False)

        # Deny with custom message
        CheckResult(allowed=False, message="You don't have access to this private view")

        # Continue with permission checks (pre-check only)
        CheckResult(allowed=None)
    """
    allowed: Optional[bool]
    message: Optional[str] = None


# Permission tuple format: (module, resource, action)
PermissionTuple: TypeAlias = Tuple[str, str, str]

# Nested permission structure for complex AND/OR logic
# Can be:
#   - A single permission tuple: ("MODULE", "resource", "action")
#   - A dict with "AND" key: {"AND": [permission1, permission2, ...]}
#   - A dict with "OR" key: {"OR": [permission1, permission2, ...]}
# These can be nested arbitrarily deep.
#
# Examples:
#   # Simple: user needs VIEW permission
#   ("ENTITY", "resource", "VIEW")
#
#   # AND: user needs both VIEW and EDIT
#   {"AND": [("ENTITY", "resource", "VIEW"), ("ENTITY", "resource", "EDIT")]}
#
#   # OR: user needs either VIEW or EDIT
#   {"OR": [("ENTITY", "resource", "VIEW"), ("ENTITY", "resource", "EDIT")]}
#
#   # Nested: user needs VIEW AND (EDIT OR DELETE)
#   {"AND": [
#       ("ENTITY", "resource", "VIEW"),
#       {"OR": [
#           ("ENTITY", "resource", "EDIT"),
#           ("ENTITY", "resource", "DELETE")
#       ]}
#   ]}
PermissionNode: TypeAlias = Union[
    PermissionTuple,
    Dict[Literal["AND", "OR"], List["PermissionNode"]]
]

# Pre-check callback return type:
#   - True or CheckResult(allowed=True): Grant access immediately
#   - False or CheckResult(allowed=False): Deny access immediately
#   - None or CheckResult(allowed=None): Continue with permission checks
#   - CheckResult(allowed=False, message="..."): Deny with custom message
PreCheckResult: TypeAlias = Union[bool, None, CheckResult]

# Post-check callback return type:
#   - True or CheckResult(allowed=True): Grant access
#   - False or CheckResult(allowed=False): Deny access
#   - CheckResult(allowed=False, message="..."): Deny with custom message
PostCheckResult: TypeAlias = Union[bool, CheckResult]

# Pre-check callback: Called before permission checks
PreCheckCallback: TypeAlias = Callable[
    ["Request", "RBACService", dict],
    Awaitable[PreCheckResult]
]

# Accepts a single pre-check callback or a list of them
PreCheckCallbacks: TypeAlias = Union[PreCheckCallback, List[PreCheckCallback]]

# Post-check callback: Called after permission checks
# Receives the result of permission checks and can modify it
PostCheckCallback: TypeAlias = Callable[
    ["Request", "RBACService", dict, bool],
    Awaitable[PostCheckResult]
]
