import asyncio
import os
from bullmq_py.bullmq_sender import bullmq_sender
from bullmq_py.bullmq_delete_all_job import bullmq_delete_all_job, bullmq_delete_all_job_async
from bullmq import Queue

# Configuración para tests
test_queue_name = "calibration_queue"
redis_url = os.environ.get('REDIS_HOST', 'redis://192.168.1.163:6379')

def test_bullmq_delete_all_job_empty_queue():
    """
    Test para verificar que delete_all_job funciona correctamente con una cola vacía.
    """
    # Ejecutar delete_all_job en cola vacía
    result = bullmq_delete_all_job(worker=test_queue_name)
    
    # Verificar que el resultado es un diccionario con las claves esperadas
    assert isinstance(result, dict), "Result should be a dictionary"
    assert "total" in result, "Result should contain 'total' key"
    assert "waiting" in result, "Result should contain 'waiting' key"
    assert "active" in result, "Result should contain 'active' key"
    assert "completed" in result, "Result should contain 'completed' key"
    assert "failed" in result, "Result should contain 'failed' key"
    assert "delayed" in result, "Result should contain 'delayed' key"
    
    # En una cola vacía, todos los contadores deben ser 0
    assert result["total"] == 0, "Total deleted jobs should be 0 for empty queue"

def test_bullmq_delete_all_job_with_jobs():
    """
    Test para verificar que delete_all_job elimina correctamente los jobs existentes.
    """
    # Primero, enviar algunos jobs a la cola
    test_messages = [
        {"task": "test_1", "data": "message 1"},
        {"task": "test_2", "data": "message 2", "priority": 10},
        {"task": "test_3", "data": "message 3", "delay_sec": 1}
    ]
    
    job_ids = []
    for i, message in enumerate(test_messages):
        if "delay_sec" in message:
            job_id = bullmq_sender(
                worker=test_queue_name,
                priority=message.get("priority", 5),
                delay_sec=message["delay_sec"],
                message=message
            )
        else:
            job_id = bullmq_sender(
                worker=test_queue_name,
                priority=message.get("priority", 5),
                message=message
            )
        job_ids.append(job_id)
    
    print(f"Sent {len(job_ids)} jobs to queue: {job_ids}")
    
    # Pequeño delay para asegurar que los jobs se envíen
    import time
    time.sleep(0.5)
    
    # Ahora eliminar todos los jobs
    result = bullmq_delete_all_job(worker=test_queue_name)
    
    # Verificar que se eliminaron jobs
    assert isinstance(result, dict), "Result should be a dictionary"
    assert result["total"] >= 0, "Total deleted jobs should be >= 0"
    
    print(f"Delete result: {result}")
    
    # Verificar que la cola está vacía después de la eliminación
    # Usar la función asíncrona para verificar
    async def verify_empty_queue():
        queue = Queue(test_queue_name, {"connection": redis_url})
        try:
            # Verificar que no hay jobs esperando
            waiting_jobs = await queue.getJobs(["waiting"], 0, -1)
            waiting_count = len(waiting_jobs) if waiting_jobs else 0
            
            # Verificar que no hay jobs completados
            completed_jobs = await queue.getJobs(["completed"], 0, -1)  
            completed_count = len(completed_jobs) if completed_jobs else 0
            
            # Verificar que no hay jobs fallidos
            failed_jobs = await queue.getJobs(["failed"], 0, -1)
            failed_count = len(failed_jobs) if failed_jobs else 0
            
            await queue.close()
            
            return {
                "waiting": waiting_count,
                "completed": completed_count, 
                "failed": failed_count
            }
        except Exception as e:
            await queue.close()
            print(f"Error checking queue: {e}")
            return {"waiting": 0, "completed": 0, "failed": 0}
    
    # Verificar estado de la cola
    queue_status = asyncio.run(verify_empty_queue())
    print(f"Queue status after deletion: {queue_status}")
    
    # La cola debería estar vacía o tener muy pocos jobs
    total_remaining = queue_status["waiting"] + queue_status["completed"] + queue_status["failed"]
    assert total_remaining == 0, f"Queue should be empty after deletion, but has {total_remaining} jobs remaining"

def test_bullmq_delete_all_job_nonexistent_queue():
    """
    Test para verificar que delete_all_job maneja correctamente colas inexistentes.
    """
    nonexistent_queue = "nonexistent_queue_12345"
    
    # Ejecutar delete_all_job en cola inexistente
    result = bullmq_delete_all_job(worker=nonexistent_queue)
    
    # Debería retornar un resultado válido sin errores
    assert isinstance(result, dict), "Result should be a dictionary"
    assert result["total"] == 0, "Total deleted jobs should be 0 for nonexistent queue"

def test_bullmq_delete_all_job_async_version():
    """
    Test para verificar que la versión asíncrona funciona correctamente usando asyncio.run().
    """
    # Enviar un job a la cola
    test_message = {"task": "async_test", "data": "async delete test"}
    job_id = bullmq_sender(
        worker=test_queue_name,
        message=test_message
    )
    
    print(f"Sent job {job_id} for async delete test")
    
    # Función asíncrona para ejecutar el test
    async def run_async_test():
        # Pequeño delay para asegurar que el job se envíe
        await asyncio.sleep(0.1)
        
        # Usar la versión asíncrona para eliminar
        result = await bullmq_delete_all_job_async(worker=test_queue_name)
        return result
    
    # Ejecutar usando asyncio.run
    result = asyncio.run(run_async_test())
    
    # Verificar resultado
    assert isinstance(result, dict), "Result should be a dictionary"
    assert result["total"] >= 0, "Total deleted jobs should be >= 0"
    
    print(f"Async delete result: {result}")

def test_bullmq_delete_all_job_custom_redis_url():
    """
    Test para verificar que delete_all_job funciona con URL de Redis personalizada.
    """
    custom_redis_url = "redis://192.168.1.163:6379"
    
    # Ejecutar delete_all_job con URL personalizada
    result = bullmq_delete_all_job(
        worker=test_queue_name,
        redis_url=custom_redis_url
    )
    
    # Verificar que el resultado es válido
    assert isinstance(result, dict), "Result should be a dictionary"
    assert "total" in result, "Result should contain 'total' key"

def test_bullmq_delete_all_job_integration():
    """
    Test de integración que simula un escenario real de uso.
    """
    print("=== Integration Test: Delete All Jobs ===")
    
    # 1. Enviar múltiples jobs con diferentes configuraciones
    jobs_config = [
        {"message": {"task": "normal_job"}, "priority": 1},
        {"message": {"task": "high_priority"}, "priority": 10},
        {"message": {"task": "delayed_job"}, "priority": 5, "delay_sec": 2},
        {"message": {"task": "another_normal"}, "priority": 3}
    ]
    
    sent_jobs = []
    for config in jobs_config:
        job_id = bullmq_sender(
            worker=test_queue_name,
            priority=config["priority"],
            delay_sec=config.get("delay_sec", 0),
            message=config["message"]
        )
        sent_jobs.append(job_id)
    
    print(f"Sent {len(sent_jobs)} jobs: {sent_jobs}")
    
    # 2. Esperar un momento para que se procesen
    import time
    time.sleep(0.5)
    
    # 3. Ejecutar delete_all_job para detener abruptamente el consumo
    print("Executing emergency job deletion...")
    result = bullmq_delete_all_job(worker=test_queue_name)
    
    print(f"Deletion completed: {result}")
    
    # 4. Verificar que se eliminaron jobs
    assert result["total"] >= 0, "Should have deleted some jobs"
    
    # 5. Verificar que la cola está limpia
    async def final_check():
        queue = Queue(test_queue_name, {"connection": redis_url})
        try:
            waiting_jobs = await queue.getJobs(["waiting"], 0, -1)
            delayed_jobs = await queue.getJobs(["delayed"], 0, -1) 
            completed_jobs = await queue.getJobs(["completed"], 0, -1)
            
            waiting_count = len(waiting_jobs) if waiting_jobs else 0
            delayed_count = len(delayed_jobs) if delayed_jobs else 0
            completed_count = len(completed_jobs) if completed_jobs else 0
            
            await queue.close()
            
            return waiting_count + delayed_count + completed_count
        except Exception as e:
            await queue.close()
            return 0
    
    remaining_jobs = asyncio.run(final_check())
    print(f"Remaining jobs in queue: {remaining_jobs}")
    
    # La eliminación debería haber limpiado la cola
    assert remaining_jobs == 0, f"Queue should be empty after deletion, found {remaining_jobs} jobs"
    
    print("✅ Integration test passed - Emergency job deletion successful")

if __name__ == "__main__":
    # Ejecutar tests individuales para desarrollo
    print("Running bullmq_delete_all_job tests...")
    
    try:
        test_bullmq_delete_all_job_empty_queue()
        print("✅ Empty queue test passed")
        
        test_bullmq_delete_all_job_with_jobs() 
        print("✅ Delete jobs test passed")
        
        test_bullmq_delete_all_job_nonexistent_queue()
        print("✅ Nonexistent queue test passed")
        
        test_bullmq_delete_all_job_custom_redis_url()
        print("✅ Custom Redis URL test passed")
        
        test_bullmq_delete_all_job_async_version()
        print("✅ Async version test passed")
        
        test_bullmq_delete_all_job_integration()
        print("✅ Integration test passed")
        
        print("\n🎉 All tests passed!")
        
    except Exception as e:
        print(f"❌ Test failed: {e}")
        raise
