"""
AbuLang Profiler - Performance analysis and profiling
"""

import time
import functools
from typing import Dict, List, Callable, Any
from collections import defaultdict


class FunctionProfile:
    """Profile data for a single function"""
    
    def __init__(self, name: str):
        self.name = name
        self.call_count = 0
        self.total_time = 0.0
        self.min_time = float('inf')
        self.max_time = 0.0
        self.calls: List[float] = []
    
    def add_call(self, duration: float):
        """Record a function call"""
        self.call_count += 1
        self.total_time += duration
        self.min_time = min(self.min_time, duration)
        self.max_time = max(self.max_time, duration)
        self.calls.append(duration)
    
    def get_average(self) -> float:
        """Get average execution time"""
        return self.total_time / self.call_count if self.call_count > 0 else 0.0
    
    def get_stats(self) -> Dict:
        """Get profile statistics"""
        return {
            "name": self.name,
            "calls": self.call_count,
            "total_time": self.total_time,
            "average_time": self.get_average(),
            "min_time": self.min_time if self.min_time != float('inf') else 0.0,
            "max_time": self.max_time
        }


class Profiler:
    """Main profiler for AbuLang code"""
    
    def __init__(self):
        self.profiles: Dict[str, FunctionProfile] = {}
        self.enabled = False
        self.start_time = None
    
    def enable(self):
        """Enable profiling"""
        self.enabled = True
        self.start_time = time.time()
    
    def disable(self):
        """Disable profiling"""
        self.enabled = False
    
    def profile_function(self, func: Callable) -> Callable:
        """Decorator to profile a function"""
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if not self.enabled:
                return func(*args, **kwargs)
            
            start = time.time()
            result = func(*args, **kwargs)
            duration = time.time() - start
            
            func_name = func.__name__
            if func_name not in self.profiles:
                self.profiles[func_name] = FunctionProfile(func_name)
            
            self.profiles[func_name].add_call(duration)
            return result
        
        return wrapper
    
    def profile_code_block(self, name: str, code_func: Callable) -> Any:
        """Profile a code block"""
        if not self.enabled:
            return code_func()
        
        start = time.time()
        result = code_func()
        duration = time.time() - start
        
        if name not in self.profiles:
            self.profiles[name] = FunctionProfile(name)
        
        self.profiles[name].add_call(duration)
        return result
    
    def get_profile(self, name: str) -> Dict:
        """Get profile for specific function"""
        if name in self.profiles:
            return self.profiles[name].get_stats()
        return None
    
    def get_all_profiles(self) -> List[Dict]:
        """Get all profiles sorted by total time"""
        profiles = [p.get_stats() for p in self.profiles.values()]
        return sorted(profiles, key=lambda x: x['total_time'], reverse=True)
    
    def get_report(self) -> str:
        """Get formatted profiling report"""
        if not self.profiles:
            return "No profiling data available"
        
        report = "\n=== AbuLang Profiler Report ===\n"
        report += f"Total Runtime: {time.time() - self.start_time:.4f}s\n\n"
        
        report += f"{'Function':<30} {'Calls':<8} {'Total (s)':<12} {'Avg (s)':<12} {'Min (s)':<12} {'Max (s)':<12}\n"
        report += "-" * 86 + "\n"
        
        for profile in self.get_all_profiles():
            report += f"{profile['name']:<30} {profile['calls']:<8} {profile['total_time']:<12.6f} {profile['average_time']:<12.6f} {profile['min_time']:<12.6f} {profile['max_time']:<12.6f}\n"
        
        return report
    
    def clear(self):
        """Clear all profiling data"""
        self.profiles.clear()


# Global profiler instance
_profiler = Profiler()


def get_profiler() -> Profiler:
    """Get global profiler"""
    return _profiler
