
import functools
import time
import json
from typing import Callable, Any
# Assuming blackboard singleton is available via swarm interface
# In a real scenario, this would import the active singleton
try:
    from swarms.blackboard import get_blackboard, EntryType
except ImportError:
    # Fallback/Mock for testing
    def get_blackboard(): return None

def reflexion_loop(max_retries: int = 2):
    """
    Apply Reflexion Pattern: Act -> Observe -> Critique -> Refine.
    
    If the decorated function raises an Exception or returns {'success': False},
    this loop waits, logs the error, and retries.
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            bb = get_blackboard()
            attempts = 0
            
            while attempts <= max_retries:
                try:
                    # ACT
                    result = func(*args, **kwargs)
                    
                    # OBSERVE (Check for implicit failure in dict return)
                    if isinstance(result, dict) and result.get('success') is False:
                        raise ValueError(f"Task Failed Logic: {result.get('error')}")
                        
                    # SUCCESS
                    if bb:
                        # Log Mastery (Positive reinforcement)
                        bb.write(
                            entry_type=EntryType.FINDING, 
                            content={"action": func.__name__, "result": "SUCCESS"},
                            author="reflexion_system",
                            confidence=1.0
                        )
                    return result

                except Exception as e:
                    # CRITIQUE: Analyze Error Type
                    attempts += 1
                    error_msg = str(e)
                    error_type = type(e).__name__
                    
                    # ⚠️ FATAL ERROR CHECK
                    is_fatal = any(x in error_msg.lower() for x in ['401', '403', 'auth', 'permission', 'fatal'])
                    
                    if is_fatal:
                        print(f"🛑 [REFLEXION] ABORT: Fatal Error detected ({error_type}): {error_msg}")
                        if bb:
                            bb.write(
                                entry_type=EntryType.FINDING,
                                content={"action": func.__name__, "error": error_msg, "status": "FATAL"},
                                author="reflexion_system",
                                confidence=0.0
                            )
                        raise e # Re-raise immediately, do not retry
                        
                    print(f"⚠️ [REFLEXION] {func.__name__} Failed (Attempt {attempts}/{max_retries}): {error_msg}")
                    
                    if bb:
                        # Log Retry for Audit
                        bb.write(
                            entry_type=EntryType.FINDING,
                            content={"action": func.__name__, "error": error_msg, "attempt": attempts},
                            author="reflexion_system", 
                            confidence=0.0
                        )
                    
                    if attempts > max_retries:
                        print(f"❌ [REFLEXION] CRITICAL FAILURE: {func.__name__} exhausted retries.")
                        raise e
                    
                    # REFINE (Backoff)
                    print(f"  Start Refinement Phase...")
                    time.sleep(2 * attempts) # Exponential Backoff
            
        return wrapper
    return decorator
