
import asyncio
import os
import time
from bullmq import Queue
import logging
from typing import Dict, List, Optional

# Configurar logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

async def get_queue_stats(queue_name: str, redis_url: str = None) -> Dict:
    """
    Obtiene estadísticas detalladas de una cola específica.
    
    Args:
        queue_name: Nombre de la cola
        redis_url: URL de Redis (opcional)
    
    Returns:
        dict: Estadísticas de la cola
    """
    if redis_url is None:
        redis_url = os.environ.get('REDIS_HOST', 'redis://192.168.1.163:6379')
    
    try:
        queue = Queue(queue_name, {"connection": redis_url})
        
        # Obtener estadísticas básicas
        stats = {
            "queue_name": queue_name,
            "waiting": 0,
            "active": 0,
            "completed": 0,
            "failed": 0,
            "delayed": 0,
            "paused": 0,
            "total_jobs": 0
        }
        
        # Obtener jobs por estado
        try:
            waiting_jobs = await queue.getJobs(["waiting"], 0, -1)
            stats["waiting"] = len(waiting_jobs) if waiting_jobs else 0
        except:
            stats["waiting"] = 0
            
        try:
            active_jobs = await queue.getJobs(["active"], 0, -1)
            stats["active"] = len(active_jobs) if active_jobs else 0
        except:
            stats["active"] = 0
            
        try:
            completed_jobs = await queue.getJobs(["completed"], 0, -1)
            stats["completed"] = len(completed_jobs) if completed_jobs else 0
        except:
            stats["completed"] = 0
            
        try:
            failed_jobs = await queue.getJobs(["failed"], 0, -1)
            stats["failed"] = len(failed_jobs) if failed_jobs else 0
        except:
            stats["failed"] = 0
            
        try:
            delayed_jobs = await queue.getJobs(["delayed"], 0, -1)
            stats["delayed"] = len(delayed_jobs) if delayed_jobs else 0
        except:
            stats["delayed"] = 0
            
        try:
            paused_jobs = await queue.getJobs(["paused"], 0, -1)
            stats["paused"] = len(paused_jobs) if paused_jobs else 0
        except:
            stats["paused"] = 0
        
        # Calcular total de jobs
        stats["total_jobs"] = sum([
            stats["waiting"], 
            stats["active"], 
            stats["completed"], 
            stats["failed"], 
            stats["delayed"],
            stats["paused"]
        ])
        
        # Agregar información adicional
        stats["status"] = "healthy" if stats["failed"] < stats["completed"] / 2 else "warning"
        stats["processing_rate"] = stats["completed"] / max(stats["total_jobs"], 1) * 100
        
        await queue.close()
        return stats
        
    except Exception as e:
        logger.error(f"Error getting stats for queue '{queue_name}': {e}")
        return {
            "queue_name": queue_name,
            "error": str(e),
            "waiting": 0,
            "active": 0,
            "completed": 0,
            "failed": 0,
            "delayed": 0,
            "paused": 0,
            "total_jobs": 0,
            "status": "error",
            "processing_rate": 0
        }

def bullmq_visibility_summary(queue_names: Optional[List[str]] = None, redis_url: str = None) -> Dict:
    """
    Proporciona un resumen general del estado de todas las colas de BullMQ.
    
    Args:
        queue_names: Lista de nombres de colas a consultar (opcional)
        redis_url: URL de Redis (opcional)
    
    Returns:
        dict: Resumen general de todas las colas
    """
    if queue_names is None:
        # Colas por defecto comunes
        queue_names = [
            "test_queue", 
            "priority_test_queue", 
            "activation_test_queue",
            "delay_test_queue",
            "calibration",
            "processing",
            "email"
        ]
    
    async def get_all_stats():
        all_stats = []
        for queue_name in queue_names:
            stats = await get_queue_stats(queue_name, redis_url)
            if "error" not in stats:  # Solo incluir colas que funcionan
                all_stats.append(stats)
        
        return all_stats
    
    try:
        # Obtener estadísticas de todas las colas
        all_queue_stats = asyncio.run(get_all_stats())
        
        if not all_queue_stats:
            return {
                "status": "no_queues",
                "message": "No se encontraron colas activas",
                "total_queues": 0
            }
        
        # Calcular resumen general
        summary = {
            "timestamp": time.time(),
            "total_queues": len(all_queue_stats),
            "active_queues": len([q for q in all_queue_stats if q["total_jobs"] > 0]),
            "total_waiting": sum(q["waiting"] for q in all_queue_stats),
            "total_active": sum(q["active"] for q in all_queue_stats),
            "total_completed": sum(q["completed"] for q in all_queue_stats),
            "total_failed": sum(q["failed"] for q in all_queue_stats),
            "total_delayed": sum(q["delayed"] for q in all_queue_stats),
            "total_paused": sum(q["paused"] for q in all_queue_stats),
            "total_jobs": sum(q["total_jobs"] for q in all_queue_stats),
        }
        
        # Calcular métricas adicionales
        if summary["total_jobs"] > 0:
            summary["success_rate"] = (summary["total_completed"] / summary["total_jobs"]) * 100
            summary["failure_rate"] = (summary["total_failed"] / summary["total_jobs"]) * 100
        else:
            summary["success_rate"] = 0
            summary["failure_rate"] = 0
        
        # Determinar estado general
        if summary["total_failed"] == 0:
            summary["overall_status"] = "healthy"
        elif summary["failure_rate"] < 10:
            summary["overall_status"] = "warning"
        else:
            summary["overall_status"] = "critical"
        
        # Top colas por actividad
        summary["most_active_queues"] = sorted(
            [{"name": q["queue_name"], "total_jobs": q["total_jobs"]} for q in all_queue_stats],
            key=lambda x: x["total_jobs"],
            reverse=True
        )[:5]
        
        # Colas con problemas
        summary["problematic_queues"] = [
            {"name": q["queue_name"], "failed": q["failed"], "total": q["total_jobs"]}
            for q in all_queue_stats 
            if q["failed"] > 0
        ]
        
        return summary
        
    except Exception as e:
        logger.error(f"Error getting visibility summary: {e}")
        return {
            "status": "error",
            "message": f"Error obteniendo resumen: {str(e)}",
            "timestamp": time.time()
        }

def bullmq_visibility_worker_summary(queue_names: Optional[List[str]] = None, redis_url: str = None) -> Dict:
    """
    Proporciona un resumen detallado del estado de workers por cola.
    
    Args:
        queue_names: Lista de nombres de colas a consultar (opcional)
        redis_url: URL de Redis (opcional)
    
    Returns:
        dict: Resumen detallado por worker/cola
    """
    if queue_names is None:
        queue_names = [
            "test_queue",
            "priority_test_queue", 
            "calibration",
            "processing",
            "email",
            "delay_test_queue"
        ]
    
    async def get_all_worker_stats():
        worker_stats = {}
        for queue_name in queue_names:
            stats = await get_queue_stats(queue_name, redis_url)
            if "error" not in stats:
                worker_stats[queue_name] = {
                    "queue_name": queue_name,
                    "pending_jobs": stats["waiting"],
                    "active_jobs": stats["active"],
                    "completed_jobs": stats["completed"],
                    "failed_jobs": stats["failed"],
                    "delayed_jobs": stats["delayed"],
                    "paused_jobs": stats["paused"],
                    "total_jobs": stats["total_jobs"],
                    "success_rate": stats["processing_rate"],
                    "status": stats["status"],
                    "health_score": min(100, max(0, 100 - (stats["failed"] * 10)))
                }
        
        return worker_stats
    
    try:
        worker_data = asyncio.run(get_all_worker_stats())
        
        if not worker_data:
            return {
                "status": "no_workers",
                "message": "No se encontraron workers activos",
                "workers": {}
            }
        
        # Agregar resumen general por worker
        result = {
            "timestamp": time.time(),
            "total_workers": len(worker_data),
            "healthy_workers": len([w for w in worker_data.values() if w["status"] == "healthy"]),
            "workers": worker_data
        }
        
        # Agregar métricas agregadas
        if worker_data:
            result["summary"] = {
                "total_pending": sum(w["pending_jobs"] for w in worker_data.values()),
                "total_active": sum(w["active_jobs"] for w in worker_data.values()),
                "total_completed": sum(w["completed_jobs"] for w in worker_data.values()),
                "total_failed": sum(w["failed_jobs"] for w in worker_data.values()),
                "total_delayed": sum(w["delayed_jobs"] for w in worker_data.values()),
                "average_health": sum(w["health_score"] for w in worker_data.values()) / len(worker_data)
            }
        
        return result
        
    except Exception as e:
        logger.error(f"Error getting worker summary: {e}")
        return {
            "status": "error", 
            "message": f"Error obteniendo resumen de workers: {str(e)}",
            "workers": {},
            "timestamp": time.time()
        }

def get_queue_health(queue_name: str, redis_url: str = None) -> Dict:
    """
    Función síncrona para obtener la salud de una cola específica.
    
    Args:
        queue_name: Nombre de la cola
        redis_url: URL de Redis (opcional)
    
    Returns:
        dict: Estado de salud de la cola
    """
    try:
        stats = asyncio.run(get_queue_stats(queue_name, redis_url))
        
        health = {
            "queue_name": queue_name,
            "is_healthy": stats.get("status") == "healthy",
            "total_jobs": stats.get("total_jobs", 0),
            "pending": stats.get("waiting", 0),
            "processing": stats.get("active", 0),
            "failed": stats.get("failed", 0),
            "success_rate": stats.get("processing_rate", 0),
            "recommendations": []
        }
        
        # Agregar recomendaciones basadas en el estado
        if health["failed"] > 0:
            health["recommendations"].append("Revisar trabajos fallidos")
        
        if health["pending"] > 50:
            health["recommendations"].append("Considerar agregar más workers")
        
        if health["success_rate"] < 80:
            health["recommendations"].append("Investigar causas de fallos")
        
        if not health["recommendations"]:
            health["recommendations"].append("Cola funcionando correctamente")
        
        return health
        
    except Exception as e:
        return {
            "queue_name": queue_name,
            "is_healthy": False,
            "error": str(e),
            "recommendations": ["Error al conectar con la cola"]
        }

def bullmq_visibility_realtime(queue_names: Optional[List[str]] = None, redis_url: str = None) -> Dict:
    """
    Proporciona información en tiempo real de las colas especificadas.
    
    Args:
        queue_names: Lista de colas a monitorear
        redis_url: URL de Redis (opcional)
    
    Returns:
        dict: Información en tiempo real
    """
    if queue_names is None:
        queue_names = ["test_queue", "calibration", "processing"]
    
    realtime_data = {
        "timestamp": time.time(),
        "queues": {}
    }
    
    for queue_name in queue_names:
        health = get_queue_health(queue_name, redis_url)
        realtime_data["queues"][queue_name] = health
    
    # Calcular métricas generales
    total_pending = sum(q.get("pending", 0) for q in realtime_data["queues"].values())
    total_processing = sum(q.get("processing", 0) for q in realtime_data["queues"].values())
    total_failed = sum(q.get("failed", 0) for q in realtime_data["queues"].values())
    
    realtime_data["system_status"] = {
        "total_pending": total_pending,
        "total_processing": total_processing,
        "total_failed": total_failed,
        "active_queues": len([q for q in realtime_data["queues"].values() if q.get("total_jobs", 0) > 0]),
        "healthy_queues": len([q for q in realtime_data["queues"].values() if q.get("is_healthy", False)])
    }
    
    # Determinar estado general del sistema
    healthy_ratio = realtime_data["system_status"]["healthy_queues"] / len(queue_names) if queue_names else 0
    
    if healthy_ratio == 1.0:
        realtime_data["system_status"]["overall_health"] = "excellent"
    elif healthy_ratio >= 0.8:
        realtime_data["system_status"]["overall_health"] = "good"
    elif healthy_ratio >= 0.6:
        realtime_data["system_status"]["overall_health"] = "warning"
    else:
        realtime_data["system_status"]["overall_health"] = "critical"
    
    return realtime_data

# Función de ejemplo para testing
if __name__ == "__main__":
    # Ejemplo de uso de las funciones de visibilidad
    
    print("=== BullMQ Visibility Demo ===")
    
    try:
        # Resumen general
        print("\n1. Resumen General:")
        summary = bullmq_visibility_summary()
        print(f"   Total colas: {summary.get('total_queues', 0)}")
        print(f"   Jobs pendientes: {summary.get('total_waiting', 0)}")
        print(f"   Jobs completados: {summary.get('total_completed', 0)}")
        print(f"   Estado general: {summary.get('overall_status', 'unknown')}")
        
        # Resumen por worker
        print("\n2. Resumen por Worker:")
        worker_summary = bullmq_visibility_worker_summary()
        for worker_name, worker_data in worker_summary.get("workers", {}).items():
            print(f"   {worker_name}:")
            print(f"     - Pendientes: {worker_data.get('pending_jobs', 0)}")
            print(f"     - Completados: {worker_data.get('completed_jobs', 0)}")
            print(f"     - Estado: {worker_data.get('status', 'unknown')}")
        
        # Información en tiempo real
        print("\n3. Tiempo Real:")
        realtime = bullmq_visibility_realtime()
        print(f"   Estado del sistema: {realtime.get('system_status', {}).get('overall_health', 'unknown')}")
        print(f"   Colas saludables: {realtime.get('system_status', {}).get('healthy_queues', 0)}")
        
        # Salud de cola específica
        print("\n4. Salud de Cola Específica (test_queue):")
        health = get_queue_health("test_queue")
        print(f"   Saludable: {health.get('is_healthy', False)}")
        print(f"   Recomendaciones: {health.get('recommendations', [])}")
        
    except Exception as e:
        print(f"Error en el demo: {e}")

