#!/usr/bin/env python3
"""
Fast Test Performance Measurement Tool for Wasot

This tool uses cargo test with timing output to measure test execution times
without the compilation overhead of running each test individually.
"""

import subprocess
import re
import sys
import json
from typing import List, Dict, Tuple
from dataclasses import dataclass

@dataclass
class TestResult:
    name: str
    duration_ms: float
    status: str

def run_tests_with_timing() -> List[TestResult]:
    """Run all tests with timing information"""
    print("🔍 Running all tests with timing information...")
    
    try:
        # Run tests with timing and capture output
        result = subprocess.run(
            ["cargo", "test", "--lib", "--", "-Z", "unstable-options", "--report-time"],
            capture_output=True,
            text=True,
            cwd="/home/tom/Projects/wasot",
            env={"RUSTC_BOOTSTRAP": "1", **dict(subprocess.os.environ)}
        )
        
        if result.returncode not in [0, 101]:  # 101 = some tests failed but that's ok
            print(f"❌ Failed to run tests: {result.stderr}")
            return []
        
        # Parse timing information from output
        results = []
        output_lines = result.stdout.split('\n')
        
        for line in output_lines:
            # Look for test result lines with timing: "test foo::bar ... ok <XXXms>"
            if " ... " in line and ("ok" in line or "FAILED" in line):
                # Extract test name and timing
                parts = line.split(" ... ")
                if len(parts) >= 2:
                    test_name = parts[0].replace("test ", "").strip()
                    result_part = parts[1].strip()
                    
                    # Determine status
                    if "ok" in result_part:
                        status = "ok"
                    elif "FAILED" in result_part:
                        status = "failed"
                    else:
                        status = "unknown"
                    
                    # Extract timing if present
                    timing_match = re.search(r'<(\d+(?:\.\d+)?)ms>', result_part)
                    if timing_match:
                        duration_ms = float(timing_match.group(1))
                    else:
                        # Default very small duration if no timing info
                        duration_ms = 1.0
                    
                    results.append(TestResult(test_name, duration_ms, status))
        
        print(f"📊 Parsed timing for {len(results)} tests")
        return results
        
    except Exception as e:
        print(f"❌ Error running tests with timing: {e}")
        return []

def run_alternative_timing() -> List[TestResult]:
    """Alternative approach: run tests and parse standard output for timing patterns"""
    print("🔍 Running tests and parsing output for timing patterns...")
    
    try:
        # Run tests and capture all output
        result = subprocess.run(
            ["cargo", "test", "--lib"],
            capture_output=True,
            text=True,
            cwd="/home/tom/Projects/wasot"
        )
        
        # Parse the final summary for timing
        results = []
        output_lines = result.stdout.split('\n')
        
        # Look for the test results section
        in_test_results = False
        for line in output_lines:
            line = line.strip()
            
            if line.startswith("test result:"):
                # Extract timing from final summary like "finished in 9.25s"
                timing_match = re.search(r'finished in ([\d\.]+)s', line)
                if timing_match:
                    total_seconds = float(timing_match.group(1))
                    print(f"📊 Total test time: {total_seconds:.2f}s")
                break
            
            # Parse individual test lines
            if line.startswith("test ") and (" ... " in line):
                parts = line.split(" ... ")
                if len(parts) >= 2:
                    test_name = parts[0].replace("test ", "")
                    result_part = parts[1]
                    
                    if "ok" in result_part:
                        status = "ok"
                    elif "FAILED" in result_part:
                        status = "failed"
                    else:
                        status = "unknown"
                    
                    # Since we don't have individual timings, estimate based on patterns
                    duration_ms = estimate_test_duration(test_name)
                    results.append(TestResult(test_name, duration_ms, status))
        
        return results
        
    except Exception as e:
        print(f"❌ Error running alternative timing: {e}")
        return []

def estimate_test_duration(test_name: str) -> float:
    """Estimate test duration based on test name patterns"""
    # Known slow patterns
    if "fuzz" in test_name.lower():
        return 2000.0  # 2 seconds for fuzz tests
    elif "honey_badger" in test_name.lower():
        return 50.0   # Honey badger tests seem slower
    elif "property_based" in test_name.lower():
        return 6000.0  # Property based tests are very slow
    elif "performance" in test_name.lower():
        return 500.0   # Performance tests likely slower
    elif "stress" in test_name.lower():
        return 200.0   # Stress tests moderately slow
    elif "extremely_long" in test_name.lower():
        return 800.0   # Long line tests
    elif "generated_syntax_tests" in test_name:
        return 4.0     # Generated syntax tests are numerous but individually fast
    else:
        return 2.0     # Default for regular tests

def run_sampling_approach() -> List[TestResult]:
    """Sample individual tests to get real timing data"""
    print("🔍 Sampling individual tests for accurate timing...")
    
    # Get a sample of tests to measure individually
    try:
        result = subprocess.run(
            ["cargo", "test", "--lib", "--", "--list"],
            capture_output=True,
            text=True,
            cwd="/home/tom/Projects/wasot"
        )
        
        all_tests = []
        for line in result.stdout.split('\n'):
            if line.strip().endswith(': test'):
                test_name = line.strip().replace(': test', '')
                all_tests.append(test_name)
        
        # Sample key tests that are likely to be slow
        sample_tests = []
        keywords = ['fuzz', 'honey_badger', 'property_based', 'performance', 'stress', 'extremely_long']
        
        for test in all_tests:
            for keyword in keywords:
                if keyword in test.lower():
                    sample_tests.append(test)
                    break
        
        # Add a few random regular tests
        import random
        regular_tests = [t for t in all_tests if not any(k in t.lower() for k in keywords)]
        sample_tests.extend(random.sample(regular_tests, min(10, len(regular_tests))))
        
        print(f"📊 Measuring {len(sample_tests)} sample tests individually...")
        
        results = []
        for test_name in sample_tests:
            print(f"   Testing {test_name[:50]}...", end="", flush=True)
            
            import time
            start_time = time.time()
            
            result = subprocess.run(
                ["cargo", "test", "--lib", test_name, "--", "--exact"],
                capture_output=True,
                text=True,
                cwd="/home/tom/Projects/wasot"
            )
            
            end_time = time.time()
            duration_ms = (end_time - start_time) * 1000
            
            if "test result: ok" in result.stdout:
                status = "ok"
            elif "test result: FAILED" in result.stdout:
                status = "failed"
            else:
                status = "ignored"
            
            results.append(TestResult(test_name, duration_ms, status))
            print(f" {duration_ms:.0f}ms ({status})")
        
        return results
        
    except Exception as e:
        print(f"❌ Error in sampling approach: {e}")
        return []

def main():
    print("🚀 Wasot Fast Test Performance Analyzer")
    print("=======================================")
    print("This tool identifies tests that should be marked as slow (>100ms)")
    print()
    
    # Try the sampling approach for more accurate results
    results = run_sampling_approach()
    
    if not results:
        print("❌ Could not measure test performance!")
        sys.exit(1)
    
    # Sort by duration
    results.sort(key=lambda x: x.duration_ms, reverse=True)
    
    # Find slow tests
    slow_tests = [r for r in results if r.duration_ms > 100 and r.status == "ok"]
    
    print()
    print("📊 ANALYSIS COMPLETE")
    print("===================")
    
    print(f"Sample tests measured: {len(results)}")
    print(f"Slow tests found (>100ms): {len(slow_tests)}")
    print()
    
    # Show all measured tests
    print("📊 MEASURED TEST PERFORMANCE")
    print("============================")
    for result in results:
        status_icon = "✅" if result.status == "ok" else "❌" if result.status == "failed" else "⚠️"
        duration_str = f"{result.duration_ms:.0f}ms"
        slow_marker = " 🐌" if result.duration_ms > 100 else ""
        print(f"{status_icon} {duration_str:>8s} - {result.name}{slow_marker}")
    
    if slow_tests:
        print()
        print("🚨 TESTS TO MARK AS SLOW (>100ms)")
        print("=================================")
        for result in slow_tests:
            print(f"   {result.duration_ms:.0f}ms - {result.name}")
        
        print()
        print("💡 These tests should be marked with #[ignore = \"slow\"] attribute")
        
        # Show file locations
        print()
        print("📂 Files to update:")
        files_to_check = set()
        for result in slow_tests:
            parts = result.name.split("::")
            if len(parts) >= 2:
                module_path = "/".join(parts[:-2]) + ".rs"
                files_to_check.add(f"src/{module_path}")
        
        for file_path in sorted(files_to_check):
            print(f"   {file_path}")
    else:
        print("🎉 No slow tests found in sample!")
    
    # Save results
    results_file = "/home/tom/Projects/wasot/test_performance_sample.json"
    with open(results_file, 'w') as f:
        json.dump([{
            'name': r.name,
            'duration_ms': r.duration_ms,
            'status': r.status
        } for r in results], f, indent=2)
    
    print(f"📄 Results saved to: {results_file}")

if __name__ == "__main__":
    main()