"""
Contexts resource functional tests.
"""

import time
from .base_test import BaseTestRunner
from models.contexts import ContextCreate, ContextUpdate
from exceptions import ValidationError


class ContextsTestRunner(BaseTestRunner):
    """Test runner for Contexts resource."""
    
    def run_test(self) -> bool:
        """Test context CRUD operations."""
        print("\n2. Testing Contexts Resource...")
        
        try:
            # Test create context
            context_data = ContextCreate(
                name="Test Business Rules",
                description="Functional test context",
                content="Business rule: Active customers have status = 'active' and last_login > 30 days ago",
                is_always_displayed=True
            )
            
            context = self.client.contexts.create(
                project_id=self.test_project_id,
                name=context_data.name,
                content=context_data.content,
                description=context_data.description,
                is_always_displayed=context_data.is_always_displayed
            )
            self.created_resources['contexts'].append(context.id)
            print(f"✅ Created context: {context.id}")
            
            # Test list contexts
            contexts = self.client.contexts.list(self.test_project_id)
            print(f"✅ Listed {len(contexts)} contexts")
            
            # Test get context
            retrieved_context = self.client.contexts.get(self.test_project_id, context.id)
            print(f"✅ Retrieved context: {retrieved_context.name}")
            
            # Test update context
            updated_context = self.client.contexts.update(
                self.test_project_id,
                context.id,
                content="Updated business rule: Active customers have status = 'active'"
            )
            print("✅ Updated context content")
            
            # Test list always displayed contexts
            always_contexts = self.client.contexts.list_always_displayed(self.test_project_id)
            print(f"✅ Found {len(always_contexts)} always-displayed contexts")
            
            # Test parallel bulk operations
            if not self._test_parallel_bulk_operations():
                return False
            
            # Test bulk delete
            if not self._test_bulk_delete():
                return False
            
            return True
            
        except Exception as e:
            print(f"❌ Contexts test failed: {e}")
            return False
    
    def _test_parallel_bulk_operations(self) -> bool:
        """Test parallel bulk operations functionality for contexts."""
        print("\n🚀 Testing Parallel Bulk Operations...")
        
        try:
            # Test 1: Basic parallel bulk create functionality
            if not self._test_basic_parallel_bulk_create():
                return False
            
            # Test 2: Performance comparison (parallel vs sequential)
            if not self._test_performance_comparison():
                return False
            
            # Test 3: Error handling in parallel mode
            if not self._test_parallel_error_handling():
                return False
            
            # Test 4: Edge cases
            if not self._test_parallel_edge_cases():
                return False
            
            print("✅ All parallel bulk operation tests passed!")
            return True
            
        except Exception as e:
            print(f"❌ Parallel bulk operations test failed: {e}")
            return False
    
    def _test_basic_parallel_bulk_create(self) -> bool:
        """Test basic parallel bulk create functionality."""
        print("\n  📋 Testing basic parallel bulk create...")
        
        # Create test data with different business contexts
        test_contexts = [
            {
                "name": f"Business Rule {i}",
                "content": f"Rule {i}: All transactions over ${i*1000} require manager approval",
                "description": f"Business rule for transaction approval level {i}",
                "is_always_displayed": i % 2 == 0
            }
            for i in range(1, 6)
        ]
        
        # Add more diverse contexts
        test_contexts.extend([
            {
                "name": "Customer Status Rules",
                "content": "Active customers: status = 'active' AND last_login > 30 days ago",
                "description": "Rules for determining active customer status"
            },
            {
                "name": "Product Categories",
                "content": "Electronics: category_id IN (1,2,3); Clothing: category_id IN (4,5,6)",
                "description": "Product categorization rules",
                "is_always_displayed": True
            },
            {
                "name": "Discount Eligibility",
                "content": "Premium customers get 15% discount; Regular customers get 5% discount",
                "description": "Customer discount tier rules"
            }
        ])
        
        # Test parallel execution (default)
        start_time = time.time()
        parallel_results = self.client.contexts.bulk_create(
            self.test_project_id, 
            test_contexts,
            parallel=True
        )
        parallel_time = time.time() - start_time
        
        # Store created IDs for cleanup
        for result in parallel_results:
            self.created_resources['contexts'].append(result.id)
        
        # Verify results
        if len(parallel_results) != len(test_contexts):
            print(f"❌ Expected {len(test_contexts)} results, got {len(parallel_results)}")
            return False
        
        # Verify all contexts were created with correct data
        for i, (original, result) in enumerate(zip(test_contexts, parallel_results)):
            if result.name != original["name"]:
                print(f"❌ Context {i}: name mismatch")
                return False
            if result.content != original["content"]:
                print(f"❌ Context {i}: content mismatch")
                return False
            if result.description != original.get("description"):
                print(f"❌ Context {i}: description mismatch")
                return False
            if result.is_always_displayed != original.get("is_always_displayed", False):
                print(f"❌ Context {i}: is_always_displayed mismatch")
                return False
        
        print(f"    ✅ Created {len(parallel_results)} contexts in parallel ({parallel_time:.2f}s)")
        return True
    
    def _test_performance_comparison(self) -> bool:
        """Test performance comparison between parallel and sequential execution."""
        print("\n  ⚡ Testing performance comparison...")
        
        # Create test data (smaller set for performance test)
        test_contexts = [
            {
                "name": f"Performance Rule {i}",
                "content": f"Performance test rule {i}: Some business logic here",
                "description": f"Performance test context {i}"
            }
            for i in range(1, 7)  # 6 contexts for performance test
        ]
        
        # Test sequential execution
        start_time = time.time()
        sequential_results = self.client.contexts.bulk_create(
            self.test_project_id,
            test_contexts,
            parallel=False
        )
        sequential_time = time.time() - start_time
        
        # Store created IDs for cleanup
        for result in sequential_results:
            self.created_resources['contexts'].append(result.id)
        
        # Create another set for parallel test
        parallel_test_contexts = [
            {
                "name": f"Parallel Rule {i}",
                "content": f"Parallel test rule {i}: Some business logic here",
                "description": f"Parallel test context {i}"
            }
            for i in range(1, 7)
        ]
        
        # Test parallel execution
        start_time = time.time()
        parallel_results = self.client.contexts.bulk_create(
            self.test_project_id,
            parallel_test_contexts,
            parallel=True
        )
        parallel_time = time.time() - start_time
        
        # Store created IDs for cleanup
        for result in parallel_results:
            self.created_resources['contexts'].append(result.id)
        
        # Verify both produced same number of results
        if len(sequential_results) != len(parallel_results):
            print(f"❌ Result count mismatch: sequential={len(sequential_results)}, parallel={len(parallel_results)}")
            return False
        
        # Calculate performance improvement
        if parallel_time > 0:
            speedup = sequential_time / parallel_time
            print(f"    ✅ Sequential: {sequential_time:.2f}s, Parallel: {parallel_time:.2f}s")
            print(f"    📈 Speedup: {speedup:.2f}x")
            
            # Parallel should be faster (or at least not significantly slower)
            if speedup < 0.5:  # Allow some overhead for small datasets
                print(f"    ⚠️  Warning: Parallel execution was slower than expected")
        else:
            print(f"    ✅ Sequential: {sequential_time:.2f}s, Parallel: {parallel_time:.2f}s")
        
        return True
    
    def _test_parallel_error_handling(self) -> bool:
        """Test error handling in parallel mode."""
        print("\n  🚨 Testing parallel error handling...")
        
        # Test with invalid data that should trigger validation errors
        test_contexts = [
            # Valid context
            {
                "name": "Valid Rule",
                "content": "This is a valid business rule",
                "description": "Valid context"
            },
            # Invalid context (empty name)
            {
                "name": "",
                "content": "This context has an empty name",
                "description": "Invalid context with empty name"
            },
            # Another valid context
            {
                "name": "Another Valid Rule",
                "content": "Another valid business rule",
                "description": "Another valid context"
            }
        ]
        
        # Test that validation catches errors before parallel execution
        try:
            self.client.contexts.bulk_create(
                self.test_project_id,
                test_contexts,
                parallel=True
            )
            # If we get here, the API might be more lenient than expected
            print("    ⚠️  API accepted contexts that were expected to fail - validation may be lenient")
            print("    ✅ Parallel execution completed without errors")
        except ValidationError as e:
            if "Bulk validation failed" in str(e):
                print("    ✅ Validation correctly caught errors before parallel execution")
            else:
                print(f"    ✅ Validation caught errors as expected: {e}")
        except Exception as e:
            print(f"    ✅ Error handling working correctly: {e}")
        
        # Test empty list handling
        try:
            empty_results = self.client.contexts.bulk_create(
                self.test_project_id,
                [],
                parallel=True
            )
            if len(empty_results) == 0:
                print("    ✅ Empty list handled correctly")
            else:
                print(f"    ❌ Expected empty results, got {len(empty_results)}")
                return False
        except Exception as e:
            print(f"    ❌ Empty list test failed: {e}")
            return False
        
        return True
    
    def _test_bulk_delete(self) -> bool:
        """Test bulk delete functionality."""
        print("\n  🗑️  Testing bulk delete...")
        
        # Create test items for bulk deletion
        items_to_delete = []
        for i in range(5):
            context = self.client.contexts.create(
                project_id=self.test_project_id,
                name=f"Bulk Delete Test {i}",
                content=f"Test context {i} to be bulk deleted",
                description=f"Bulk delete test context {i}"
            )
            items_to_delete.append(context.id)
            # Don't add to created_resources - will be bulk deleted
        
        # Test bulk delete
        result = self.client.contexts.bulk_delete(
            self.test_project_id,
            items_to_delete
        )
        
        # Verify results
        if result['deleted_count'] != 5:
            print(f"❌ Expected 5 deletions, got {result['deleted_count']}")
            return False
        
        if result.get('failed_ids'):
            print(f"❌ Unexpected failures: {result['failed_ids']}")
            return False
        
        # Verify items are actually deleted
        remaining = self.client.contexts.list(self.test_project_id)
        remaining_ids = [item.id for item in remaining]
        
        for deleted_id in items_to_delete:
            if deleted_id in remaining_ids:
                print(f"❌ Item {deleted_id} still exists after bulk delete")
                return False
        
        print(f"    ✅ Successfully bulk deleted {len(items_to_delete)} items")
        
        # Test error handling - try to delete non-existent IDs
        fake_ids = ["fake_id_1", "fake_id_2"]
        try:
            result = self.client.contexts.bulk_delete(
                self.test_project_id,
                fake_ids
            )
            if result.get('failed_ids'):
                print("    ✅ Error handling working correctly for invalid IDs")
            else:
                print("    ⚠️  API accepted invalid IDs without errors")
        except Exception as e:
            print(f"    ✅ Exception raised for invalid IDs: {type(e).__name__}")
        
        # Test empty list
        try:
            result = self.client.contexts.bulk_delete(
                self.test_project_id,
                []
            )
            print(f"    ❌ Empty list should raise ValidationError")
            return False
        except ValidationError:
            print("    ✅ Empty list correctly raises ValidationError")
        
        return True
    
    def _test_parallel_edge_cases(self) -> bool:
        """Test edge cases for parallel bulk operations."""
        print("\n  🔬 Testing edge cases...")
        
        # Test single item (should use sequential path)
        single_context = [{
            "name": "Single Edge Case",
            "content": "Single context test",
            "description": "Single context test"
        }]
        
        try:
            results = self.client.contexts.bulk_create(
                self.test_project_id,
                single_context,
                parallel=True
            )
            
            if len(results) == 1:
                self.created_resources['contexts'].append(results[0].id)
                print("    ✅ Single item handled correctly")
            else:
                print(f"❌ Expected 1 result, got {len(results)}")
                return False
        except Exception as e:
            print(f"❌ Single item test failed: {e}")
            return False
        
        # Test custom max_workers
        test_contexts = [
            {
                "name": f"Max Workers Test {i}",
                "content": f"Max workers test context {i}",
                "description": f"Max workers test {i}"
            }
            for i in range(4)
        ]
        
        try:
            results = self.client.contexts.bulk_create(
                self.test_project_id,
                test_contexts,
                parallel=True,
                max_workers=2
            )
            
            if len(results) == 4:
                for result in results:
                    self.created_resources['contexts'].append(result.id)
                print("    ✅ Custom max_workers handled correctly")
            else:
                print(f"❌ Expected 4 results, got {len(results)}")
                return False
        except Exception as e:
            print(f"❌ Custom max_workers test failed: {e}")
            return False
        
        return True
