#!/usr/bin/env python3
"""
Textual Testing Framework - Simplified testing for Textual apps
"""

import asyncio
import sys
from pathlib import Path
from typing import Optional, Dict, Any, List, Callable
from contextlib import asynccontextmanager

class TextualTestRunner:
    """Test runner for Textual applications"""
    
    def __init__(self, app_class):
        self.app_class = app_class
        self.app = None
        
    @asynccontextmanager
    async def run_app(self, **app_kwargs):
        """Context manager to run app for testing"""
        self.app = self.app_class(**app_kwargs)
        
        try:
            # Start the app
            async with self.app.run_test() as pilot:
                yield pilot
        finally:
            self.app = None
            
    async def test_widget_exists(self, selector: str) -> bool:
        """Test if a widget exists"""
        if not self.app:
            return False
            
        try:
            widget = self.app.query_one(selector)
            return widget is not None
        except:
            return False
            
    async def test_widget_visible(self, selector: str) -> bool:
        """Test if a widget is visible"""
        if not self.app:
            return False
            
        try:
            widget = self.app.query_one(selector)
            return widget.visible if widget else False
        except:
            return False
            
    async def test_widget_text(self, selector: str, expected_text: str) -> bool:
        """Test if a widget contains expected text"""
        if not self.app:
            return False
            
        try:
            widget = self.app.query_one(selector)
            if hasattr(widget, 'label'):
                return expected_text in str(widget.label)
            elif hasattr(widget, 'text'):
                return expected_text in str(widget.text)
            return False
        except:
            return False
            
    async def test_button_count(self, container_selector: str, expected_count: int) -> bool:
        """Test if a container has expected number of buttons"""
        if not self.app:
            return False
            
        try:
            container = self.app.query_one(container_selector)
            buttons = container.query("Button")
            return len(buttons) == expected_count
        except:
            return False
            
    async def simulate_key_press(self, key: str):
        """Simulate a key press"""
        if self.app:
            self.app.action_key(key)
            await asyncio.sleep(0.1)  # Allow time for processing
            
    async def simulate_button_click(self, button_selector: str):
        """Simulate clicking a button"""
        if not self.app:
            return False
            
        try:
            button = self.app.query_one(button_selector)
            if button:
                button.press()
                await asyncio.sleep(0.1)
                return True
        except:
            pass
        return False

class TextualTestSuite:
    """Test suite for organizing Textual tests"""
    
    def __init__(self, name: str):
        self.name = name
        self.tests = []
        self.setup_func = None
        self.teardown_func = None
        
    def setup(self, func):
        """Decorator for setup function"""
        self.setup_func = func
        return func
        
    def teardown(self, func):
        """Decorator for teardown function"""
        self.teardown_func = func
        return func
        
    def test(self, name: str):
        """Decorator for test functions"""
        def decorator(func):
            self.tests.append((name, func))
            return func
        return decorator
        
    async def run(self, runner: TextualTestRunner) -> Dict[str, Any]:
        """Run all tests in the suite"""
        results = {
            'suite': self.name,
            'total': len(self.tests),
            'passed': 0,
            'failed': 0,
            'errors': [],
            'details': []
        }
        
        print(f"🧪 Running test suite: {self.name}")
        print("=" * 50)
        
        for test_name, test_func in self.tests:
            try:
                # Setup
                if self.setup_func:
                    await self.setup_func(runner)
                    
                # Run test
                print(f"  Running: {test_name}...", end="")
                success = await test_func(runner)
                
                if success:
                    print(" ✅ PASS")
                    results['passed'] += 1
                else:
                    print(" ❌ FAIL")
                    results['failed'] += 1
                    
                results['details'].append({
                    'name': test_name,
                    'passed': success,
                    'error': None
                })
                
                # Teardown
                if self.teardown_func:
                    await self.teardown_func(runner)
                    
            except Exception as e:
                print(f" 💥 ERROR: {e}")
                results['failed'] += 1
                results['errors'].append(f"{test_name}: {e}")
                results['details'].append({
                    'name': test_name,
                    'passed': False,
                    'error': str(e)
                })
                
        return results

def create_sample_test_suite():
    """Create a sample test suite for the StreamLens app"""
    
    suite = TextualTestSuite("StreamLens Button Tests")
    
    @suite.test("Overview button exists")
    async def test_overview_button(runner):
        async with runner.run_app() as pilot:
            return await runner.test_widget_exists("#btn-overview")
    
    @suite.test("Overview button has correct text")
    async def test_overview_button_text(runner):
        async with runner.run_app() as pilot:
            return await runner.test_widget_text("#btn-overview", "Overview")
    
    @suite.test("Filter bar contains buttons")
    async def test_filter_bar_buttons(runner):
        async with runner.run_app() as pilot:
            # Allow time for buttons to be created
            await asyncio.sleep(1)
            return await runner.test_button_count("#filter-bar", 1)  # At least overview button
    
    @suite.test("Key press navigation works")
    async def test_key_navigation(runner):
        async with runner.run_app() as pilot:
            await runner.simulate_key_press("1")
            await asyncio.sleep(0.5)
            # Check if overview is selected (would need app-specific logic)
            return True  # Placeholder
    
    return suite

async def main():
    print("🧪 Textual Testing Framework")
    print("=" * 50)
    
    # Example usage with StreamLens
    try:
        from analyzer.tui.textual.app_v2 import StreamLensAppV2
        
        runner = TextualTestRunner(StreamLensAppV2)
        suite = create_sample_test_suite()
        
        results = await suite.run(runner)
        
        print(f"\n📊 Test Results for {results['suite']}:")
        print(f"   Total: {results['total']}")
        print(f"   Passed: {results['passed']}")
        print(f"   Failed: {results['failed']}")
        
        if results['errors']:
            print(f"\n❌ Errors:")
            for error in results['errors']:
                print(f"   {error}")
                
        if results['passed'] == results['total']:
            print(f"\n🎉 All tests passed!")
        else:
            print(f"\n⚠️  {results['failed']} tests failed")
            
    except ImportError:
        print("StreamLens app not found. Here's how to use this framework:")
        print("\n1. Import your Textual app class")
        print("2. Create a TextualTestRunner with your app class")
        print("3. Create test suites with TextualTestSuite")
        print("4. Run tests with suite.run(runner)")
        
        print(f"\n📝 Example usage:")
        print(f"""
from your_app import YourTextualApp
from textual_test_framework import TextualTestRunner, TextualTestSuite

async def run_tests():
    runner = TextualTestRunner(YourTextualApp)
    suite = TextualTestSuite("My Tests")
    
    @suite.test("Widget exists")
    async def test_widget(runner):
        async with runner.run_app() as pilot:
            return await runner.test_widget_exists("#my-widget")
    
    results = await suite.run(runner)
    print(f"Passed: {{results['passed']}}/{{results['total']}}")

asyncio.run(run_tests())
        """)

if __name__ == "__main__":
    asyncio.run(main())