#!/usr/bin/env python3
"""
Critical Performance Analysis for CutySoup
This test investigates the performance issues reported on Windows remote environments
and determines if CSQL integration or Python/C++ boundary issues are the root cause.
"""

import time
import sys
import os
import statistics
import traceback
from typing import Dict, List, Any
import gc

# Import BeautifulSoup4 for comparison
try:
    from bs4 import BeautifulSoup
    from bs4.element import Tag as BS4Tag
    BS4_AVAILABLE = True
except ImportError:
    BS4_AVAILABLE = False

# Import CutySoup
try:
    from cutysoup import CutySoup, Tag, NavigableString
    from cutysoup.csql import CSQLEngine, CSQLQuery
    CUTYSOUP_AVAILABLE = True
except ImportError as e:
    print(f"❌ CutySoup import failed: {e}")
    CUTYSOUP_AVAILABLE = False


class CriticalPerformanceAnalyzer:
    """Critical analysis of CutySoup performance issues"""
    
    def __init__(self):
        self.test_html = self._generate_test_html()
        self.results = {}
        self.detailed_timings = {}
        
    def _generate_test_html(self) -> str:
        """Generate comprehensive test HTML document"""
        return """
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Performance Test Document</title>
            <style>
                .highlight { background-color: yellow; }
                .important { color: red; font-weight: bold; }
            </style>
        </head>
        <body>
            <header id="main-header" class="site-header">
                <h1>Performance Test Page</h1>
                <nav class="main-nav">
                    <ul>
                        <li><a href="#section1" class="nav-link">Section 1</a></li>
                        <li><a href="#section2" class="nav-link">Section 2</a></li>
                        <li><a href="#section3" class="nav-link">Section 3</a></li>
                    </ul>
                </nav>
            </header>
            
            <main id="content">
                <section id="section1" class="content-section highlight">
                    <h2>Test Section 1</h2>
                    <p class="intro">This is an introduction paragraph with <strong>bold</strong> text.</p>
                    <div class="data-container">
                        <table class="data-table">
                            <thead>
                                <tr><th>Name</th><th>Value</th><th>Category</th></tr>
                            </thead>
                            <tbody>
                                <tr><td>Item 1</td><td data-value="100">$100.00</td><td class="category-a">Type A</td></tr>
                                <tr><td>Item 2</td><td data-value="250">$250.50</td><td class="category-b">Type B</td></tr>
                                <tr><td>Item 3</td><td data-value="75">$75.25</td><td class="category-a">Type A</td></tr>
                                <tr><td>Item 4</td><td data-value="300">$300.99</td><td class="category-c">Type C</td></tr>
                                <tr><td>Item 5</td><td data-value="150">$150.75</td><td class="category-b">Type B</td></tr>
                            </tbody>
                        </table>
                    </div>
                </section>
                
                <section id="section2" class="content-section">
                    <h2>Test Section 2</h2>
                    <div class="article-list">
                        <article class="article-item important">
                            <h3>Article 1</h3>
                            <p class="excerpt">This is the first article excerpt...</p>
                            <div class="meta"><span class="date">2024-01-01</span><span class="author">Author 1</span></div>
                        </article>
                        <article class="article-item">
                            <h3>Article 2</h3>
                            <p class="excerpt">This is the second article excerpt...</p>
                            <div class="meta"><span class="date">2024-01-02</span><span class="author">Author 2</span></div>
                        </article>
                        <article class="article-item important">
                            <h3>Article 3</h3>
                            <p class="excerpt">This is the third article excerpt...</p>
                            <div class="meta"><span class="date">2024-01-03</span><span class="author">Author 3</span></div>
                        </article>
                    </div>
                </section>
                
                <section id="section3" class="content-section highlight">
                    <h2>Complex Nested Structure</h2>
                    <div class="nested-container">
                        <div class="level-1">
                            <div class="level-2">
                                <div class="level-3">
                                    <div class="level-4">
                                        <p class="deep-content">Deep nested content</p>
                                        <ul class="deep-list">
                                            <li class="list-item">Item A</li>
                                            <li class="list-item">Item B</li>
                                            <li class="list-item">Item C</li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </main>
            
            <footer class="site-footer">
                <p>&copy; 2024 Performance Test. All rights reserved.</p>
                <div class="footer-links">
                    <a href="#privacy" class="footer-link">Privacy</a>
                    <a href="#terms" class="footer-link">Terms</a>
                    <a href="#contact" class="footer-link">Contact</a>
                </div>
            </footer>
        </body>
        </html>
        """
    
    def _time_operation(self, operation_func, iterations: int = 5) -> Dict[str, float]:
        """Time an operation with multiple iterations for statistical accuracy"""
        times = []
        gc.collect()  # Clean up before timing
        
        for _ in range(iterations):
            start_time = time.perf_counter()
            try:
                result = operation_func()
                end_time = time.perf_counter()
                times.append((end_time - start_time) * 1000)  # Convert to milliseconds
            except Exception as e:
                print(f"⚠️ Operation failed: {e}")
                return {"mean": float('inf'), "median": float('inf'), "min": float('inf'), "max": float('inf')}
        
        return {
            "mean": statistics.mean(times),
            "median": statistics.median(times),
            "min": min(times),
            "max": max(times),
            "std": statistics.stdev(times) if len(times) > 1 else 0
        }
    
    def test_parsing_performance(self):
        """Test HTML parsing performance"""
        print("🔍 Testing HTML Parsing Performance...")
        
        # Test CutySoup parsing
        if CUTYSOUP_AVAILABLE:
            cutysoup_times = self._time_operation(lambda: CutySoup(self.test_html), 10)
            self.results["cutysoup_parsing"] = cutysoup_times
        else:
            self.results["cutysoup_parsing"] = {"error": "CutySoup not available"}
        
        # Test BeautifulSoup4 parsing  
        if BS4_AVAILABLE:
            bs4_times = self._time_operation(lambda: BeautifulSoup(self.test_html, 'html.parser'), 10)
            self.results["bs4_parsing"] = bs4_times
        else:
            self.results["bs4_parsing"] = {"error": "BeautifulSoup4 not available"}
    
    def test_find_operations(self):
        """Test find/find_all performance"""
        print("🔍 Testing Find Operations Performance...")
        
        if CUTYSOUP_AVAILABLE:
            cs_soup = CutySoup(self.test_html)
            
            # Test various find operations
            cutysoup_find_all = self._time_operation(lambda: cs_soup.find_all('div'))
            cutysoup_find_class = self._time_operation(lambda: cs_soup.find_all(class_='article-item'))
            cutysoup_find_nested = self._time_operation(lambda: cs_soup.find_all('p', class_='excerpt'))
            cutysoup_find_complex = self._time_operation(lambda: cs_soup.find_all('tr'))
            
            self.results["cutysoup_find_all"] = cutysoup_find_all
            self.results["cutysoup_find_class"] = cutysoup_find_class  
            self.results["cutysoup_find_nested"] = cutysoup_find_nested
            self.results["cutysoup_find_complex"] = cutysoup_find_complex
        
        if BS4_AVAILABLE:
            bs4_soup = BeautifulSoup(self.test_html, 'html.parser')
            
            bs4_find_all = self._time_operation(lambda: bs4_soup.find_all('div'))
            bs4_find_class = self._time_operation(lambda: bs4_soup.find_all(class_='article-item'))
            bs4_find_nested = self._time_operation(lambda: bs4_soup.find_all('p', class_='excerpt'))
            bs4_find_complex = self._time_operation(lambda: bs4_soup.find_all('tr'))
            
            self.results["bs4_find_all"] = bs4_find_all
            self.results["bs4_find_class"] = bs4_find_class
            self.results["bs4_find_nested"] = bs4_find_nested
            self.results["bs4_find_complex"] = bs4_find_complex
    
    def test_css_selector_performance(self):
        """Test CSS selector performance"""
        print("🔍 Testing CSS Selector Performance...")
        
        if CUTYSOUP_AVAILABLE:
            cs_soup = CutySoup(self.test_html)
            
            cutysoup_css_simple = self._time_operation(lambda: cs_soup.select('div'))
            cutysoup_css_class = self._time_operation(lambda: cs_soup.select('.article-item'))
            cutysoup_css_descendant = self._time_operation(lambda: cs_soup.select('section p'))
            cutysoup_css_complex = self._time_operation(lambda: cs_soup.select('tr td[data-value]'))
            cutysoup_css_pseudo = self._time_operation(lambda: cs_soup.select('li:first-child'))
            
            self.results["cutysoup_css_simple"] = cutysoup_css_simple
            self.results["cutysoup_css_class"] = cutysoup_css_class
            self.results["cutysoup_css_descendant"] = cutysoup_css_descendant
            self.results["cutysoup_css_complex"] = cutysoup_css_complex
            self.results["cutysoup_css_pseudo"] = cutysoup_css_pseudo
        
        if BS4_AVAILABLE:
            bs4_soup = BeautifulSoup(self.test_html, 'html.parser')
            
            bs4_css_simple = self._time_operation(lambda: bs4_soup.select('div'))
            bs4_css_class = self._time_operation(lambda: bs4_soup.select('.article-item'))
            bs4_css_descendant = self._time_operation(lambda: bs4_soup.select('section p'))
            bs4_css_complex = self._time_operation(lambda: bs4_soup.select('tr td[data-value]'))
            bs4_css_pseudo = self._time_operation(lambda: bs4_soup.select('li:first-child'))
            
            self.results["bs4_css_simple"] = bs4_css_simple
            self.results["bs4_css_class"] = bs4_css_class
            self.results["bs4_css_descendant"] = bs4_css_descendant
            self.results["bs4_css_complex"] = bs4_css_complex
            self.results["bs4_css_pseudo"] = bs4_css_pseudo
    
    def test_csql_performance(self):
        """Test CSQL performance impact"""
        print("🔍 Testing CSQL Performance Impact...")
        
        if not CUTYSOUP_AVAILABLE:
            self.results["csql_impact"] = {"error": "CutySoup not available"}
            return
            
        cs_soup = CutySoup(self.test_html)
        
        # Test equivalent operations with CSQL vs standard methods
        def csql_query():
            query = CSQLQuery(cs_soup)
            return query.execute({
                "articles": {
                    "selector": ".article-item",
                    "type": "list",
                    "fields": {
                        "title": "h3",
                        "excerpt": ".excerpt",
                        "date": ".date"
                    }
                }
            })
        
        def standard_query():
            articles = cs_soup.select('.article-item')
            results = []
            for article in articles:
                title_elem = article.select_one('h3')
                excerpt_elem = article.select_one('.excerpt')
                date_elem = article.select_one('.date')
                
                results.append({
                    "title": title_elem.get_text().strip() if title_elem else None,
                    "excerpt": excerpt_elem.get_text().strip() if excerpt_elem else None,
                    "date": date_elem.get_text().strip() if date_elem else None
                })
            return {"articles": results}
        
        csql_times = self._time_operation(csql_query, 5)
        standard_times = self._time_operation(standard_query, 5)
        
        self.results["csql_query"] = csql_times
        self.results["standard_query"] = standard_times
    
    def test_text_extraction_performance(self):
        """Test text extraction performance"""
        print("🔍 Testing Text Extraction Performance...")
        
        if CUTYSOUP_AVAILABLE:
            cs_soup = CutySoup(self.test_html)
            
            cutysoup_get_text = self._time_operation(lambda: cs_soup.get_text())
            cutysoup_stripped_strings = self._time_operation(lambda: list(cs_soup.stripped_strings))
            cutysoup_strings = self._time_operation(lambda: list(cs_soup.strings))
            
            self.results["cutysoup_get_text"] = cutysoup_get_text
            self.results["cutysoup_stripped_strings"] = cutysoup_stripped_strings
            self.results["cutysoup_strings"] = cutysoup_strings
        
        if BS4_AVAILABLE:
            bs4_soup = BeautifulSoup(self.test_html, 'html.parser')
            
            bs4_get_text = self._time_operation(lambda: bs4_soup.get_text())
            bs4_stripped_strings = self._time_operation(lambda: list(bs4_soup.stripped_strings))
            bs4_strings = self._time_operation(lambda: list(bs4_soup.strings))
            
            self.results["bs4_get_text"] = bs4_get_text
            self.results["bs4_stripped_strings"] = bs4_stripped_strings
            self.results["bs4_strings"] = bs4_strings
    
    def test_navigation_performance(self):
        """Test tree navigation performance"""
        print("🔍 Testing Tree Navigation Performance...")
        
        if CUTYSOUP_AVAILABLE:
            cs_soup = CutySoup(self.test_html)
            first_div = cs_soup.find('div')
            
            if first_div:
                cutysoup_children = self._time_operation(lambda: list(first_div.children))
                cutysoup_descendants = self._time_operation(lambda: list(first_div.descendants))
                cutysoup_parents = self._time_operation(lambda: list(first_div.parents))
                
                self.results["cutysoup_children"] = cutysoup_children
                self.results["cutysoup_descendants"] = cutysoup_descendants
                self.results["cutysoup_parents"] = cutysoup_parents
        
        if BS4_AVAILABLE:
            bs4_soup = BeautifulSoup(self.test_html, 'html.parser')
            first_div = bs4_soup.find('div')
            
            if first_div:
                bs4_children = self._time_operation(lambda: list(first_div.children))
                bs4_descendants = self._time_operation(lambda: list(first_div.descendants))
                bs4_parents = self._time_operation(lambda: list(first_div.parents))
                
                self.results["bs4_children"] = bs4_children
                self.results["bs4_descendants"] = bs4_descendants
                self.results["bs4_parents"] = bs4_parents
    
    def analyze_python_cpp_boundary_cost(self):
        """Analyze the cost of Python/C++ boundary crossings"""
        print("🔍 Analyzing Python/C++ Boundary Costs...")
        
        if not CUTYSOUP_AVAILABLE:
            return
            
        cs_soup = CutySoup(self.test_html)
        
        # Test repeated small operations (high boundary crossing cost)
        def many_small_finds():
            for _ in range(100):
                cs_soup.find('div')
        
        # Test single large operation (low boundary crossing cost)
        def single_large_find():
            cs_soup.find_all('div')
        
        # Test attribute access patterns
        def attribute_access_test():
            elements = cs_soup.find_all('td')
            for elem in elements:
                _ = elem.get('data-value', '')
                _ = elem.get_text()
                _ = elem.name
        
        many_small_times = self._time_operation(many_small_finds, 3)
        single_large_times = self._time_operation(single_large_find, 3)
        attribute_times = self._time_operation(attribute_access_test, 3)
        
        self.results["many_small_operations"] = many_small_times
        self.results["single_large_operation"] = single_large_times
        self.results["attribute_access_pattern"] = attribute_times
    
    def run_all_tests(self):
        """Run all performance tests"""
        print("🚀 Starting Critical Performance Analysis...")
        print(f"Python version: {sys.version}")
        print(f"Platform: {sys.platform}")
        print(f"CutySoup available: {CUTYSOUP_AVAILABLE}")
        print(f"BeautifulSoup4 available: {BS4_AVAILABLE}")
        print("-" * 60)
        
        test_methods = [
            self.test_parsing_performance,
            self.test_find_operations,
            self.test_css_selector_performance,
            self.test_csql_performance,
            self.test_text_extraction_performance,
            self.test_navigation_performance,
            self.analyze_python_cpp_boundary_cost
        ]
        
        for test_method in test_methods:
            try:
                test_method()
            except Exception as e:
                print(f"❌ Test {test_method.__name__} failed: {e}")
                traceback.print_exc()
        
        print("\n" + "="*60)
        print("📊 CRITICAL PERFORMANCE ANALYSIS RESULTS")
        print("="*60)
        
        self._generate_performance_report()
    
    def _generate_performance_report(self):
        """Generate a critical performance analysis report"""
        print("\n🎯 PERFORMANCE BOTTLENECK ANALYSIS:")
        
        # Analyze parsing performance
        if "cutysoup_parsing" in self.results and "bs4_parsing" in self.results:
            cs_parse = self.results["cutysoup_parsing"].get("mean", float('inf'))
            bs4_parse = self.results["bs4_parsing"].get("mean", float('inf'))
            
            if cs_parse != float('inf') and bs4_parse != float('inf'):
                ratio = cs_parse / bs4_parse
                print(f"\n📈 PARSING PERFORMANCE:")
                print(f"   CutySoup: {cs_parse:.2f}ms (mean)")
                print(f"   BeautifulSoup4: {bs4_parse:.2f}ms (mean)")
                print(f"   Ratio: {ratio:.2f}x ({'SLOWER' if ratio > 1 else 'FASTER'} than BS4)")
                
                if ratio > 1:
                    print(f"   ⚠️ CRITICAL: CutySoup parsing is {ratio:.2f}x SLOWER than expected!")
        
        # Analyze find operations
        find_operations = [
            ("find_all", "cutysoup_find_all", "bs4_find_all"),
            ("find by class", "cutysoup_find_class", "bs4_find_class"),
            ("nested find", "cutysoup_find_nested", "bs4_find_nested"),
            ("complex find", "cutysoup_find_complex", "bs4_find_complex")
        ]
        
        print(f"\n🔍 FIND OPERATIONS PERFORMANCE:")
        for op_name, cs_key, bs4_key in find_operations:
            if cs_key in self.results and bs4_key in self.results:
                cs_time = self.results[cs_key].get("mean", float('inf'))
                bs4_time = self.results[bs4_key].get("mean", float('inf'))
                
                if cs_time != float('inf') and bs4_time != float('inf'):
                    ratio = cs_time / bs4_time
                    print(f"   {op_name}: {ratio:.2f}x ({'SLOWER' if ratio > 1 else 'FASTER'})")
                    if ratio > 1:
                        print(f"     ⚠️ CutySoup: {cs_time:.2f}ms vs BS4: {bs4_time:.2f}ms")
        
        # Analyze CSS selector performance
        css_operations = [
            ("simple CSS", "cutysoup_css_simple", "bs4_css_simple"),
            ("class selector", "cutysoup_css_class", "bs4_css_class"),
            ("descendant selector", "cutysoup_css_descendant", "bs4_css_descendant"),
            ("complex selector", "cutysoup_css_complex", "bs4_css_complex"),
            ("pseudo selector", "cutysoup_css_pseudo", "bs4_css_pseudo")
        ]
        
        print(f"\n🎨 CSS SELECTOR PERFORMANCE:")
        for op_name, cs_key, bs4_key in css_operations:
            if cs_key in self.results and bs4_key in self.results:
                cs_time = self.results[cs_key].get("mean", float('inf'))
                bs4_time = self.results[bs4_key].get("mean", float('inf'))
                
                if cs_time != float('inf') and bs4_time != float('inf'):
                    ratio = cs_time / bs4_time
                    print(f"   {op_name}: {ratio:.2f}x ({'SLOWER' if ratio > 1 else 'FASTER'})")
                    if ratio > 1.5:
                        print(f"     ⚠️ SLOW: CutySoup: {cs_time:.2f}ms vs BS4: {bs4_time:.2f}ms")
        
        # CSQL Analysis
        if "csql_query" in self.results and "standard_query" in self.results:
            csql_time = self.results["csql_query"].get("mean", float('inf'))
            std_time = self.results["standard_query"].get("mean", float('inf'))
            
            if csql_time != float('inf') and std_time != float('inf'):
                ratio = csql_time / std_time
                print(f"\n🗃️ CSQL IMPACT ANALYSIS:")
                print(f"   CSQL Query: {csql_time:.2f}ms")
                print(f"   Standard Query: {std_time:.2f}ms")
                print(f"   CSQL Overhead: {ratio:.2f}x ({'SLOWER' if ratio > 1 else 'FASTER'})")
                
                if ratio > 1:
                    print(f"   ⚠️ CSQL adds {((ratio - 1) * 100):.1f}% overhead!")
        
        # Python/C++ boundary analysis
        if "many_small_operations" in self.results and "single_large_operation" in self.results:
            many_small = self.results["many_small_operations"].get("mean", float('inf'))
            single_large = self.results["single_large_operation"].get("mean", float('inf'))
            
            print(f"\n🔄 PYTHON/C++ BOUNDARY ANALYSIS:")
            print(f"   Many small operations (100x find): {many_small:.2f}ms")
            print(f"   Single large operation (find_all): {single_large:.2f}ms")
            
            if many_small != float('inf') and single_large != float('inf'):
                # Calculate per-operation cost
                per_small_op = many_small / 100
                print(f"   Per small operation cost: {per_small_op:.3f}ms")
                print(f"   Boundary crossing overhead: {'HIGH' if per_small_op > 0.1 else 'LOW'}")
        
        # Generate critical assessment
        print(f"\n💥 CRITICAL ISSUES IDENTIFIED:")
        critical_issues = []
        
        # Check for parsing issues
        if "cutysoup_parsing" in self.results and "bs4_parsing" in self.results:
            cs_parse = self.results["cutysoup_parsing"].get("mean", float('inf'))
            bs4_parse = self.results["bs4_parsing"].get("mean", float('inf'))
            if cs_parse != float('inf') and bs4_parse != float('inf') and cs_parse / bs4_parse > 1.5:
                critical_issues.append("Parsing performance significantly worse than BeautifulSoup4")
        
        # Check for operation issues
        slower_operations = 0
        total_operations = 0
        
        all_comparisons = find_operations + css_operations
        for _, cs_key, bs4_key in all_comparisons:
            if cs_key in self.results and bs4_key in self.results:
                cs_time = self.results[cs_key].get("mean", float('inf'))
                bs4_time = self.results[bs4_key].get("mean", float('inf'))
                if cs_time != float('inf') and bs4_time != float('inf'):
                    total_operations += 1
                    if cs_time / bs4_time > 1:
                        slower_operations += 1
        
        if total_operations > 0:
            slower_percentage = (slower_operations / total_operations) * 100
            if slower_percentage > 70:
                critical_issues.append(f"{slower_percentage:.0f}% of operations are slower than BS4")
        
        # Check CSQL overhead
        if "csql_query" in self.results and "standard_query" in self.results:
            csql_time = self.results["csql_query"].get("mean", float('inf'))
            std_time = self.results["standard_query"].get("mean", float('inf'))
            if csql_time != float('inf') and std_time != float('inf') and csql_time / std_time > 2:
                critical_issues.append("CSQL introduces significant performance overhead")
        
        if critical_issues:
            for i, issue in enumerate(critical_issues, 1):
                print(f"   {i}. {issue}")
        else:
            print("   No critical performance issues detected")
        
        # Recommendations
        print(f"\n🔧 RECOMMENDATIONS:")
        
        # Check if CSQL is being used inappropriately
        if "csql_query" in self.results and "standard_query" in self.results:
            csql_time = self.results["csql_query"].get("mean", float('inf'))
            std_time = self.results["standard_query"].get("mean", float('inf'))
            if csql_time != float('inf') and std_time != float('inf') and csql_time > std_time * 1.5:
                print("   1. AVOID using CSQL for simple operations - use direct CutySoup methods")
                print("   2. CSQL should only be used for complex structured data extraction")
        
        # Check for boundary issues
        if "many_small_operations" in self.results:
            many_small = self.results["many_small_operations"].get("mean", float('inf'))
            if many_small != float('inf'):
                per_op = many_small / 100
                if per_op > 0.05:  # 0.05ms per operation is high for C++ calls
                    print("   3. Optimize Python/C++ boundary - batch operations when possible")
        
        # General recommendations
        parsing_slower = False
        if "cutysoup_parsing" in self.results and "bs4_parsing" in self.results:
            cs_parse = self.results["cutysoup_parsing"].get("mean", float('inf'))
            bs4_parse = self.results["bs4_parsing"].get("mean", float('inf'))
            if cs_parse != float('inf') and bs4_parse != float('inf') and cs_parse > bs4_parse:
                parsing_slower = True
                
        if parsing_slower:
            print("   4. CRITICAL: Core C++ parsing engine needs optimization")
            print("   5. Profile C++ code for performance bottlenecks")
            print("   6. Consider memory allocation patterns in C++ layer")
        
        print(f"\n🏁 CONCLUSION:")
        if critical_issues:
            print("   ❌ PERFORMANCE ISSUES CONFIRMED")
            print("   📊 Root causes: Poor C++/Python integration and/or CSQL overhead")
            print("   🎯 Focus optimization efforts on C++ layer and reduce Python crossings")
        else:
            print("   ✅ No major performance issues detected")
            print("   📊 CutySoup is performing as expected")


def main():
    """Run the critical performance analysis"""
    analyzer = CriticalPerformanceAnalyzer()
    analyzer.run_all_tests()


if __name__ == "__main__":
    main()