"""
Specification Pattern Implementation

Specifications encapsulate business rules that can be combined
using logical operators (AND, OR, NOT).
"""

from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Any


T = TypeVar('T')


class Specification(ABC, Generic[T]):
    """
    Abstract base class for specifications.
    
    Specifications encapsulate business rules and can be combined
    to create complex conditions.
    
    Usage:
        active_spec = IsActiveSpecification()
        premium_spec = IsPremiumSpecification()
        combined = active_spec & premium_spec
        
        for user in users:
            if combined.is_satisfied_by(user):
                ...
    """
    
    @abstractmethod
    def is_satisfied_by(self, candidate: T) -> bool:
        """
        Check if the candidate satisfies this specification.
        
        Args:
            candidate: The object to check
            
        Returns:
            True if specification is satisfied
        """
        pass
    
    def __and__(self, other: "Specification[T]") -> "AndSpecification[T]":
        """Combine with AND operator."""
        return AndSpecification(self, other)
    
    def __or__(self, other: "Specification[T]") -> "OrSpecification[T]":
        """Combine with OR operator."""
        return OrSpecification(self, other)
    
    def __invert__(self) -> "NotSpecification[T]":
        """Negate with NOT operator."""
        return NotSpecification(self)


class AndSpecification(Specification[T]):
    """
    Combines two specifications with AND logic.
    
    Both specifications must be satisfied.
    """
    
    def __init__(self, left: Specification[T], right: Specification[T]):
        self._left = left
        self._right = right
    
    def is_satisfied_by(self, candidate: T) -> bool:
        return (
            self._left.is_satisfied_by(candidate) and 
            self._right.is_satisfied_by(candidate)
        )


class OrSpecification(Specification[T]):
    """
    Combines two specifications with OR logic.
    
    At least one specification must be satisfied.
    """
    
    def __init__(self, left: Specification[T], right: Specification[T]):
        self._left = left
        self._right = right
    
    def is_satisfied_by(self, candidate: T) -> bool:
        return (
            self._left.is_satisfied_by(candidate) or 
            self._right.is_satisfied_by(candidate)
        )


class NotSpecification(Specification[T]):
    """
    Negates a specification.
    
    The wrapped specification must NOT be satisfied.
    """
    
    def __init__(self, spec: Specification[T]):
        self._spec = spec
    
    def is_satisfied_by(self, candidate: T) -> bool:
        return not self._spec.is_satisfied_by(candidate)


class TrueSpecification(Specification[T]):
    """Always returns True."""
    
    def is_satisfied_by(self, candidate: T) -> bool:
        return True


class FalseSpecification(Specification[T]):
    """Always returns False."""
    
    def is_satisfied_by(self, candidate: T) -> bool:
        return False


class AttributeSpecification(Specification[T]):
    """
    Generic specification that checks an attribute value.
    
    Usage:
        spec = AttributeSpecification('status', 'active')
        spec.is_satisfied_by(entity)  # True if entity.status == 'active'
    """
    
    def __init__(self, attribute: str, expected_value: Any):
        self._attribute = attribute
        self._expected_value = expected_value
    
    def is_satisfied_by(self, candidate: T) -> bool:
        actual_value = getattr(candidate, self._attribute, None)
        return actual_value == self._expected_value
