"""
Testes de integração complexos
"""
import pytest
from uuid import uuid4
from atomic_agents.integrations.langchain import AtomicOptimizer
from langchain_core.outputs import LLMResult, Generation
from langchain_core.agents import AgentAction


class TestComplexIntegration:
    def test_full_workflow_with_all_features(self):
        """Testar workflow completo com todas as features"""
        optimizer = AtomicOptimizer(
            compression=True,
            policies={
                "maxCost": 100.0,
                "maxTokens": 10000,
                "blockedTools": ["dangerous"]
            },
            ledger=True
        )
        
        # Simular workflow completo
        run_id = uuid4()
        
        # 1. LLM Start
        prompts = ["Please help me. The goal is to analyze data."]
        optimizer.on_llm_start({}, prompts, run_id=run_id)
        
        # 2. LLM End
        llm_result = LLMResult(generations=[[Generation(text="Analysis complete")]])
        optimizer.on_llm_end(llm_result, run_id=run_id)
        
        # 3. Tool call (allowed)
        action = AgentAction(tool="safe_tool", tool_input="", log="")
        optimizer.on_agent_action(action, run_id=run_id)
        
        # 4. Verificar ledger
        assert len(optimizer.ledger.entries) >= 2
        events = [e["data"]["event"] for e in optimizer.ledger.entries]
        assert "llm_start" in events
        assert "llm_end" in events
        
    def test_multiple_runs_parallel(self):
        """Testar múltiplos runs (simulando paralelo)"""
        optimizer = AtomicOptimizer(
            compression=True,
            policies={"maxCost": 1000.0},
            ledger=True
        )
        
        run_ids = [uuid4() for _ in range(10)]
        
        # Iniciar todos
        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)
        
        # Finalizar todos
        for run_id in run_ids:
            llm_result = LLMResult(generations=[[Generation(text="Done")]])
            optimizer.on_llm_end(llm_result, run_id=run_id)
        
        # Verificar que todos foram registrados
        assert len(optimizer.ledger.entries) == 20  # 10 start + 10 end
        assert len(optimizer.run_metrics) == 10
        
    def test_policy_violation_mid_workflow(self):
        """Testar violação de política no meio do workflow"""
        optimizer = AtomicOptimizer(
            compression=False,
            policies={"maxCost": 50.0},
            ledger=True
        )
        
        run_id1 = uuid4()
        optimizer.current_cost = 30.0
        optimizer.on_llm_start({}, ["test1"], run_id=run_id1)
        
        # Aumentar custo
        optimizer.current_cost = 60.0
        
        run_id2 = uuid4()
        with pytest.raises(Exception, match="Policy Violation"):
            optimizer.on_llm_start({}, ["test2"], run_id=run_id2)
        
        # Primeiro run deve ter sido registrado
        assert len(optimizer.ledger.entries) >= 1
        
    def test_compression_metrics_tracking(self):
        """Testar rastreamento de métricas de compressão"""
        optimizer = AtomicOptimizer(
            compression=True,
            ledger=False
        )
        
        run_id = uuid4()
        prompts = ["Please help me. The goal is to summarize. " * 10]
        original_size = len(prompts[0])
        
        optimizer.on_llm_start({}, prompts, run_id=run_id)
        
        # Verificar métricas
        metrics = optimizer.run_metrics.get(str(run_id))
        assert metrics is not None
        assert metrics["original"] == original_size
        assert metrics["compressed"] < original_size
        
    def test_tool_blocking_with_ledger(self):
        """Testar bloqueio de ferramenta com ledger"""
        optimizer = AtomicOptimizer(
            compression=False,
            policies={"blockedTools": ["blocked_tool"]},
            ledger=True
        )
        
        run_id = uuid4()
        action = AgentAction(tool="blocked_tool", tool_input="", log="")
        
        with pytest.raises(Exception, match="Tool Blocked"):
            optimizer.on_agent_action(action, run_id=run_id)
        
        # Ledger deve registrar o bloqueio
        events = [e["data"].get("event") for e in optimizer.ledger.entries]
        assert "tool_blocked" in events
        
    def test_cost_accumulation(self):
        """Testar acumulação de custo ao longo do tempo"""
        optimizer = AtomicOptimizer(
            compression=False,
            policies={"maxCost": 100.0},
            ledger=False
        )
        
        # Simular múltiplas chamadas acumulando custo
        for i in range(10):
            optimizer.current_cost = i * 10.0
            run_id = uuid4()
            
            if optimizer.current_cost < 100.0:
                optimizer.on_llm_start({}, ["test"], run_id=run_id)
            else:
                with pytest.raises(Exception, match="Policy Violation"):
                    optimizer.on_llm_start({}, ["test"], run_id=run_id)
                    
    def test_mixed_compression_levels(self):
        """Testar diferentes níveis de compressão"""
        from atomic_agents.core import TDLNCompressor
        
        # Testar que compressor funciona com diferentes textos
        compressor = TDLNCompressor()
        texts = [
            "Please help me.",
            "Please help me. The goal is to process.",
            "Please help me. The goal is to process. Make sure to check.",
        ]
        
        for text in texts:
            compressed = compressor.compress(text)
            assert len(compressed) <= len(text)
            
    def test_ledger_chain_verification(self):
        """Verificar integridade da cadeia do ledger em workflow completo"""
        optimizer = AtomicOptimizer(ledger=True, compression=False)
        
        run_ids = [uuid4() for _ in range(5)]
        
        for run_id in run_ids:
            optimizer.on_llm_start({}, ["test"], run_id=run_id)
            llm_result = LLMResult(generations=[[Generation(text="response")]])
            optimizer.on_llm_end(llm_result, run_id=run_id)
        
        # Verificar cadeia
        entries = optimizer.ledger.entries
        for i in range(1, len(entries)):
            assert entries[i]["previous_hash"] == entries[i-1]["hash"]


