"""
Testes de stress e performance
"""
import pytest
import time
from atomic_agents.core import TDLNCompressor, PolicyEngine, AuditLedger
from atomic_agents.integrations.langchain import AtomicOptimizer


class TestStressTDLN:
    def test_large_text_compression(self):
        """Testar compressão de texto muito grande"""
        compressor = TDLNCompressor()
        # Criar texto de 100KB
        large_text = "Please help me. The goal is to " * 2000
        start = time.time()
        result = compressor.compress(large_text)
        elapsed = time.time() - start
        assert len(result) < len(large_text)
        assert elapsed < 1.0  # Deve ser rápido
        
    def test_many_compressions(self):
        """Testar muitas compressões sequenciais"""
        compressor = TDLNCompressor()
        texts = ["Please help me. The goal is to summarize."] * 1000
        start = time.time()
        results = [compressor.compress(text) for text in texts]
        elapsed = time.time() - start
        assert len(results) == 1000
        assert elapsed < 2.0  # Deve ser rápido
        
    def test_unicode_and_special_chars(self):
        """Testar com caracteres especiais e unicode"""
        compressor = TDLNCompressor()
        special_texts = [
            "Please help me with 🚀 emoji. The goal is to process.",
            "Please help me with 中文. The goal is to analyze.",
            "Please help me with\nnewlines.\nThe goal is to parse.",
            "Please help me with\t\ttabs. The goal is to format.",
            "Please help me with \"quotes\". The goal is to escape.",
            "Please help me with 'single quotes'. The goal is to handle.",
            "Please help me with (parentheses). The goal is to parse.",
            "Please help me with [brackets]. The goal is to extract.",
        ]
        for text in special_texts:
            result = compressor.compress(text)
            assert isinstance(result, str)
            assert len(result) > 0


class TestStressPolicyEngine:
    def test_many_policy_checks(self):
        """Testar muitas verificações de política"""
        policies = {
            "maxCost": 100.0,
            "maxTokens": 10000,
            "blockedTools": ["tool1", "tool2", "tool3"]
        }
        engine = PolicyEngine(policies)
        
        start = time.time()
        for i in range(1000):
            engine.pre_check("llm_call", {"current_cost": i * 0.01})
            engine.check_tool(f"tool_{i % 10}")
        elapsed = time.time() - start
        assert elapsed < 1.0
        
    def test_large_policy_dict(self):
        """Testar com dicionário de políticas muito grande"""
        large_blocked = [f"blocked_tool_{i}" for i in range(1000)]
        policies = {
            "blockedTools": large_blocked,
            "maxCost": 1000.0,
            "maxTokens": 100000
        }
        engine = PolicyEngine(policies)
        
        # Verificar se encontra ferramenta bloqueada rapidamente
        result = engine.check_tool("blocked_tool_500")
        assert result.allowed is False
        
        # Verificar se permite ferramenta não bloqueada
        result = engine.check_tool("allowed_tool")
        assert result.allowed is True
        
    def test_edge_case_costs(self):
        """Testar valores extremos de custo"""
        policies = {"maxCost": 100.0}
        engine = PolicyEngine(policies)
        
        edge_cases = [
            (0.0, True),
            (100.0, False),  # Exatamente no limite
            (100.0000001, False),  # Acima do limite
            (99.9999999, True),  # Abaixo do limite
            (1e10, False),  # Muito grande
            (-1.0, True),  # Negativo (deve permitir)
        ]
        
        for cost, expected in edge_cases:
            result = engine.pre_check("llm_call", {"current_cost": cost})
            assert result.allowed == expected, f"Failed for cost={cost}"


class TestStressLedger:
    def test_many_ledger_entries(self):
        """Testar ledger com muitas entradas"""
        ledger = AuditLedger()
        start = time.time()
        for i in range(1000):
            ledger.record({"event": f"event_{i}", "data": f"data_{i}"})
        elapsed = time.time() - start
        
        assert len(ledger.entries) == 1000
        assert elapsed < 1.0  # Deve ser rápido
        
        # Verificar integridade da cadeia
        for i in range(1, 1000):
            assert ledger.entries[i]["previous_hash"] == ledger.entries[i-1]["hash"]
            
    def test_large_data_entries(self):
        """Testar entradas com dados muito grandes"""
        ledger = AuditLedger()
        large_data = {"data": "x" * 10000}  # 10KB de dados
        entry = ledger.record(large_data)
        assert len(entry["hash"]) == 64  # SHA256 sempre 64 chars hex
        
    def test_rapid_sequential_entries(self):
        """Testar entradas muito rápidas sequenciais"""
        ledger = AuditLedger()
        entries = []
        for i in range(100):
            entry = ledger.record({"event": f"rapid_{i}", "timestamp": time.time()})
            entries.append(entry)
            time.sleep(0.0001)  # Mínimo delay para garantir timestamps únicos
        
        # Todos devem ter hashes únicos
        hashes = [e["hash"] for e in entries]
        assert len(hashes) == len(set(hashes))  # Todos únicos


class TestStressOptimizer:
    def test_many_llm_calls(self):
        """Testar muitas chamadas LLM sequenciais"""
        optimizer = AtomicOptimizer(
            compression=True,
            policies={"maxCost": 1000.0},
            ledger=True
        )
        
        from uuid import uuid4
        from langchain_core.outputs import LLMResult, Generation
        
        start = time.time()
        for i in range(100):
            run_id = uuid4()
            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)
        
        elapsed = time.time() - start
        assert len(optimizer.ledger.entries) == 200  # 100 start + 100 end
        assert elapsed < 2.0
        
    def test_concurrent_compression(self):
        """Testar compressão concorrente (simulado)"""
        optimizer = AtomicOptimizer(compression=True, ledger=False)
        from uuid import uuid4
        
        prompts_list = [
            [f"Please help me. The goal is to process {i}."] 
            for i in range(50)
        ]
        
        start = time.time()
        for prompts in prompts_list:
            optimizer.on_llm_start({}, prompts, run_id=uuid4())
        elapsed = time.time() - start
        
        assert elapsed < 1.0
        
    def test_policy_violation_stress(self):
        """Testar muitas violações de política"""
        optimizer = AtomicOptimizer(
            compression=False,
            policies={"maxCost": 10.0},
            ledger=False
        )
        from uuid import uuid4
        
        optimizer.current_cost = 15.0
        failed_count = 0
        
        for i in range(100):
            try:
                optimizer.on_llm_start({}, ["test"], run_id=uuid4())
            except Exception as e:
                if "Policy Violation" in str(e):
                    failed_count += 1
        
        assert failed_count == 100  # Todas devem falhar


