"""
Testes de performance extremos - Battle Test Final
"""
import pytest
import time
import sys
from atomic_agents.core import TDLNCompressor, PolicyEngine, AuditLedger
from atomic_agents.integrations.langchain import AtomicOptimizer
from uuid import uuid4
from langchain_core.outputs import LLMResult, Generation


class TestExtremePerformance:
    def test_massive_throughput(self):
        """Testar throughput massivo - 10.000 operações"""
        compressor = TDLNCompressor()
        start = time.time()
        
        for i in range(10000):
            compressor.compress(f"Please help me. The goal is to process {i}.")
        
        elapsed = time.time() - start
        ops_per_sec = 10000 / elapsed
        print(f"\nThroughput: {ops_per_sec:.0f} ops/sec")
        assert elapsed < 5.0  # Deve ser muito rápido
        assert ops_per_sec > 1000  # Mínimo 1000 ops/sec
        
    def test_memory_efficiency_ledger(self):
        """Testar eficiência de memória do ledger"""
        import tracemalloc
        
        ledger = AuditLedger()
        tracemalloc.start()
        
        snapshot1 = tracemalloc.take_snapshot()
        
        # Adicionar 1000 entradas
        for i in range(1000):
            ledger.record({"event": f"event_{i}", "data": f"data_{i}"})
        
        snapshot2 = tracemalloc.take_snapshot()
        top_stats = snapshot2.compare_to(snapshot1, 'lineno')
        
        # Pegar o maior aumento de memória
        total_diff = sum(stat.size_diff for stat in top_stats[:10])
        print(f"\nMemory increase for 1000 entries: {total_diff / 1024 / 1024:.2f} MB")
        
        # Não deve usar mais de 50MB para 1000 entradas
        assert total_diff < 50 * 1024 * 1024
        
        tracemalloc.stop()
        
    def test_concurrent_simulation(self):
        """Simular uso concorrente intenso"""
        optimizer = AtomicOptimizer(
            compression=True,
            policies={"maxCost": 10000.0},
            ledger=True
        )
        
        start = time.time()
        run_ids = [uuid4() for _ in range(500)]
        
        # Simular 500 chamadas LLM
        for run_id in run_ids:
            prompts = [f"Please help me. The goal is to process {run_id}."]
            optimizer.on_llm_start({}, prompts, run_id=run_id)
            
            llm_result = LLMResult(generations=[[Generation(text="Done")]])
            optimizer.on_llm_end(llm_result, run_id=run_id)
        
        elapsed = time.time() - start
        print(f"\n500 LLM calls in {elapsed:.2f}s ({500/elapsed:.0f} calls/sec)")
        
        assert elapsed < 3.0
        assert len(optimizer.ledger.entries) == 1000  # 500 start + 500 end
        
    def test_large_policy_list_performance(self):
        """Testar performance com lista grande de ferramentas bloqueadas"""
        blocked_tools = [f"blocked_{i}" for i in range(5000)]
        policies = {"blockedTools": blocked_tools}
        engine = PolicyEngine(policies)
        
        start = time.time()
        for i in range(1000):
            tool_name = f"tool_{i % 10000}"
            engine.check_tool(tool_name)
        elapsed = time.time() - start
        
        print(f"\n1000 tool checks with 5000 blocked tools: {elapsed:.3f}s")
        assert elapsed < 1.0  # Deve ser rápido mesmo com lista grande
        
    def test_compression_quality_large_text(self):
        """Testar qualidade de compressão em texto grande"""
        compressor = TDLNCompressor()
        
        # Texto de 50KB com muitos padrões compressíveis
        large_text = "Please help me. The goal is to process. " * 1000
        
        original_size = len(large_text)
        compressed = compressor.compress(large_text)
        compressed_size = len(compressed)
        
        compression_ratio = (1 - compressed_size / original_size) * 100
        
        print(f"\nLarge text compression:")
        print(f"  Original: {original_size} chars")
        print(f"  Compressed: {compressed_size} chars")
        print(f"  Ratio: {compression_ratio:.1f}%")
        
        assert compressed_size < original_size
        assert compression_ratio > 20  # Pelo menos 20% de compressão
        
    def test_ledger_chain_integrity_under_load(self):
        """Testar integridade da cadeia sob carga"""
        ledger = AuditLedger()
        
        # Adicionar 5000 entradas rapidamente
        for i in range(5000):
            ledger.record({"event": f"event_{i}", "index": i})
        
        # Verificar integridade completa
        errors = 0
        for i in range(1, len(ledger.entries)):
            if ledger.entries[i]["previous_hash"] != ledger.entries[i-1]["hash"]:
                errors += 1
        
        assert errors == 0, f"Found {errors} chain integrity errors"
        assert len(ledger.entries) == 5000
        
    def test_mixed_workload(self):
        """Testar workload misto realista"""
        optimizer = AtomicOptimizer(
            compression=True,
            policies={
                "maxCost": 1000.0,
                "maxTokens": 50000,
                "blockedTools": ["dangerous", "unsafe"]
            },
            ledger=True
        )
        
        start = time.time()
        
        # Simular workload realista: 100 chamadas LLM, algumas com violações
        successful = 0
        failed = 0
        
        for i in range(100):
            run_id = uuid4()
            optimizer.current_cost = i * 5.0  # Custo crescente
            
            try:
                prompts = [f"Please help me. The goal is to process request {i}."]
                optimizer.on_llm_start({}, prompts, run_id=run_id)
                
                llm_result = LLMResult(generations=[[Generation(text=f"Response {i}")]])
                optimizer.on_llm_end(llm_result, run_id=run_id)
                successful += 1
            except Exception:
                failed += 1
        
        elapsed = time.time() - start
        
        print(f"\nMixed workload (100 calls):")
        print(f"  Successful: {successful}")
        print(f"  Failed: {failed}")
        print(f"  Time: {elapsed:.2f}s")
        
        assert elapsed < 2.0
        assert successful + failed == 100


