"""Test para validar que graceful_shutdown rechaza tareas nuevas (Opción B)."""

import pytest
import time
import threading
import sys
from pathlib import Path

# Agregar src al path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

from feid.agent.maestro import AgenteMaestroNASA
from feid.agent.factory import AgenteFactory


class SimpleAgent(AgenteMaestroNASA):
    """Agente simple para testing."""
    def _technical_work(self, task):
        time.sleep(0.1)  # Simular trabajo
        return f"Processed: {task}"


def test_shutdown_rechaza_tareas_nuevas():
    """
    Valida que durante graceful_shutdown, el flag accepting_tasks=False
    bloquea la entrada de nuevas tareas.
    
    Escenario:
    1. Crear agente y llenar con 20 tareas
    2. Iniciar shutdown en thread separado
    3. Esperar 0.5s para entrar en estado DRAINING
    4. Intentar enviar tarea nueva → debe fallar con RuntimeError
    """
    agent = AgenteFactory.standard(SimpleAgent, "test_shutdown")
    
    # Llenar cola con tareas
    for i in range(20):
        agent.send_task(f"Task {i}", priority=2)
    
    print(f"\n[TEST] Cola inicial: {agent.inbox.qsize()} tareas")
    
    # Iniciar shutdown en thread separado
    shutdown_thread = threading.Thread(target=agent.graceful_shutdown, kwargs={"timeout": 10})
    shutdown_thread.start()
    
    # Esperar a que entre en estado DRAINING
    time.sleep(0.5)
    
    # Validar que el flag accepting_tasks es False
    assert agent.accepting_tasks is False, "El agente debería tener accepting_tasks=False"
    assert agent.shutting_down is True, "El agente debería tener shutting_down=True"
    
    # Intentar enviar tarea nueva (debe fallar)
    with pytest.raises(RuntimeError, match="shutting down"):
        agent.send_task("New task during shutdown")
    
    print("[TEST] ✅ Tarea rechazada correctamente durante shutdown")
    
    # Esperar a que termine el shutdown
    shutdown_thread.join()
    
    # Validar estado final
    assert agent.alive is False, "El agente debería estar apagado"
    print(f"[TEST] ✅ Shutdown completado. Cola final: {agent.inbox.qsize()}")


def test_shutdown_drena_cola_antes_de_apagar():
    """
    Valida que el worker procesa la cola ANTES de apagar (alive=False).
    
    Escenario:
    1. Crear agente con 30 tareas
    2. Ejecutar graceful_shutdown con timeout generoso
    3. Validar que la mayoría de tareas fueron procesadas
    """
    agent = AgenteFactory.standard(SimpleAgent, "test_drain")
    
    # Llenar cola
    num_tasks = 30
    for i in range(num_tasks):
        agent.send_task(f"Task {i}", priority=2)
    
    print(f"\n[TEST] Cola inicial: {agent.inbox.qsize()} tareas")
    
    # Ejecutar shutdown con timeout de 15s (suficiente para drenar 30 tareas)
    stats = agent.graceful_shutdown(timeout=15.0)
    
    # Validar que la mayoría de tareas fueron procesadas
    successful = stats.get("successful_tasks", 0)
    pending = stats.get("pending_queue", 0)
    
    print(f"[TEST] Tareas exitosas: {successful}, Pendientes: {pending}")
    
    # Al menos 80% procesadas (algunas pueden quedar por timeout)
    assert successful >= num_tasks * 0.8, f"Debería procesar al menos 24 tareas, procesó {successful}"
    assert pending < num_tasks * 0.2, f"No debería quedar más del 20% pendiente, quedaron {pending}"
    
    print("[TEST] ✅ Cola drenada correctamente antes de apagar")


def test_shutdown_estados_bien_definidos():
    """
    Valida la transición de estados:
    RUNNING → DRAINING → STOPPING → STOPPED
    """
    agent = AgenteFactory.quick(SimpleAgent, "test_states")
    
    # Estado inicial
    assert agent.alive is True
    assert agent.accepting_tasks is True
    assert agent.shutting_down is False
    print("[TEST] ✅ Estado inicial RUNNING")
    
    # Agregar algunas tareas
    for i in range(10):
        agent.send_task(f"Task {i}")
    
    # Iniciar shutdown
    def do_shutdown():
        agent.graceful_shutdown(timeout=5.0)
    
    shutdown_thread = threading.Thread(target=do_shutdown)
    shutdown_thread.start()
    
    # Esperar transición a DRAINING
    time.sleep(0.3)
    assert agent.accepting_tasks is False, "Debería estar en DRAINING (accepting_tasks=False)"
    assert agent.alive is True, "Worker debería seguir vivo durante DRAINING"
    assert agent.shutting_down is True
    print("[TEST] ✅ Estado DRAINING alcanzado")
    
    # Esperar a que termine
    shutdown_thread.join()
    
    # Estado final: STOPPED
    assert agent.alive is False
    assert agent.accepting_tasks is False
    print("[TEST] ✅ Estado final STOPPED")


def test_multiple_shutdown_calls_safe():
    """
    Valida que llamar graceful_shutdown múltiples veces es seguro.
    """
    agent = AgenteFactory.quick(SimpleAgent, "test_multi")
    
    for i in range(5):
        agent.send_task(f"Task {i}")
    
    # Primera llamada
    stats1 = agent.graceful_shutdown(timeout=3.0)
    assert stats1 is not None
    print(f"[TEST] Primera shutdown completada: {stats1['shutdown_seconds']}s")
    
    # Segunda llamada (debería ser idempotente)
    stats2 = agent.graceful_shutdown(timeout=1.0)
    assert stats2 is not None
    print(f"[TEST] ✅ Segunda shutdown es segura (idempotente)")


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--tb=short"])
