from __future__ import annotations
import asyncio, threading
from agent_framework.guardrails.base import RailDecision
from agent_framework.guardrails.parallel_executor import ParallelRailExecutor
from agent_framework.guardrails.config_loader import load_guardrails_config
from agent_framework.judges.judge import JudgePipeline, JudgeResult


def test_contas_config_substitui_policies_tim_por_extensoes():
    bundle=load_guardrails_config('config/guardrails.yaml')
    codes=[r.code for r in bundle.output_rails]
    assert 'TIM_OOS' in codes and 'TIM_AOFERTA' in codes and 'TIM_REVPREC' in codes
    assert 'OOS' not in codes and 'AOFERTA' not in codes and 'REVPREC' not in codes


def test_sync_external_rail_runs_in_worker_thread():
    main=threading.current_thread().name
    class R:
        code='THREAD_TEST'
        def evaluate(self,text,ctx): return RailDecision(code=self.code,allowed=True,metadata={'thread':threading.current_thread().name})
    result=asyncio.run(ParallelRailExecutor().run('x',{},[R()]))
    assert result.results[0].metadata['thread'] != main


def test_external_judges_load_from_agent_config():
    pipeline=JudgePipeline(config_path='config/judges.yaml', llm=None)
    assert [j.name for j in pipeline.judges] == ['tim_response_quality','tim_groundedness']


def test_sync_judges_run_concurrently_in_threads():
    names=[]
    class J:
        def __init__(self,name): self.name=name
        def evaluate(self,q,a,c):
            names.append(threading.current_thread().name)
            return JudgeResult(name=self.name,score=1,passed=True)
    p=JudgePipeline(judges=[J('a'),J('b')], enabled=True)
    p.sample_rate=1.0
    results=asyncio.run(p.evaluate_all('q','answer with enough text',{}))
    assert [r.name for r in results]==['a','b']
    assert all(n != threading.current_thread().name for n in names)
