import asyncio
import os
import uuid
from typing import Dict, List, Optional, Any
from datetime import datetime, timezone
from bullmq import Queue
import logging

from .bullmq_sender import bullmq_sender, bullmq_sender_async

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

def bullmq_flow(flow_config: Dict, redis_url: str = None) -> Dict:
    """
    Función simplificada para crear flows de BullMQ (jobs padre con children).
    
    Args:
        flow_config: Diccionario con configuración del flow
            - name: Nombre del job padre
            - queueName: Nombre de la cola del job padre
            - data: Datos del job padre (opcional)
            - opts: Opciones del job padre (opcional)
            - children: Lista de jobs hijos
        redis_url: URL de Redis (opcional, usa variable de entorno por defecto)
    
    Returns:
        Dict: Información del flow creado con IDs de jobs padre e hijos
    """
    return asyncio.run(bullmq_flow_async(flow_config, redis_url))

async def bullmq_flow_async(flow_config: Dict, redis_url: str = None) -> Dict:
    """
    Versión asíncrona de bullmq_flow para uso en contextos async.
    
    Args:
        flow_config: Diccionario con configuración del flow
        redis_url: URL de Redis (opcional, usa variable de entorno por defecto)
    
    Returns:
        Dict: Información del flow creado con IDs de jobs padre e hijos
    """
    if redis_url is None:
        redis_url = os.environ.get('REDIS_HOST', 'redis://192.168.1.163:6379')
    
    # Generar ID único para el flow
    flow_id = str(uuid.uuid4())
    flow_timestamp = datetime.now(timezone.utc).isoformat()
    
    try:
        # Validar configuración básica
        if 'name' not in flow_config:
            raise ValueError("Flow config must include 'name'")
        if 'queueName' not in flow_config:
            raise ValueError("Flow config must include 'queueName'")
        
        # Extraer configuración del job padre
        parent_name = flow_config['name']
        parent_queue = flow_config['queueName']
        parent_data = flow_config.get('data', {})
        parent_opts = flow_config.get('opts', {})
        children_config = flow_config.get('children', [])
        
        logger.info(f"Creating flow '{parent_name}' with {len(children_config)} children")
        
        # Preparar datos del job padre con metadata del flow
        parent_message = {
            **parent_data,
            "_flow_id": flow_id,
            "_flow_type": "parent",
            "_flow_name": parent_name,
            "_flow_timestamp": flow_timestamp,
            "_children_count": len(children_config),
            "_children_queues": [child.get('queueName') for child in children_config]
        }
        
        # Crear job padre
        parent_priority = parent_opts.get('priority', 5)
        parent_delay = parent_opts.get('delay', 0)
        parent_job_id = parent_opts.get('jobId')
        
        # Convertir delay de milisegundos a segundos si es necesario
        if parent_delay > 1000:  # Asumir que está en milisegundos
            parent_delay = parent_delay // 1000
        
        # Usar nombre descriptivo para el job padre
        parent_job_name = parent_opts.get('jobId') or f"flow_{parent_name}_parent"
        
        parent_id = await bullmq_sender_async(
            worker=parent_queue,
            priority=parent_priority,
            delay_sec=parent_delay,
            message=parent_message,
            redis_url=redis_url,
            job_id=parent_job_name
        )
        
        logger.info(f"Parent job created: {parent_id} in queue '{parent_queue}'")
        
        # Crear jobs hijos
        children_results = []
        
        for i, child_config in enumerate(children_config):
            try:
                # Validar configuración del hijo
                if 'queueName' not in child_config:
                    logger.warning(f"Child {i} missing queueName, skipping")
                    continue
                
                child_name = child_config.get('name', f"{parent_name}_child_{i}")
                child_queue = child_config['queueName']
                child_data = child_config.get('data', {})
                child_opts = child_config.get('opts', {})
                
                # Preparar datos del job hijo con metadata del flow
                child_message = {
                    **child_data,
                    "_flow_id": flow_id,
                    "_flow_type": "child",
                    "_flow_name": parent_name,
                    "_flow_timestamp": flow_timestamp,
                    "_parent_job_id": parent_id,
                    "_parent_queue": parent_queue,
                    "_child_index": i,
                    "_child_name": child_name
                }
                
                # Configuración del job hijo
                child_priority = child_opts.get('priority', 5)
                child_delay = child_opts.get('delay', 0)
                child_job_id = child_opts.get('jobId')
                
                # Convertir delay de milisegundos a segundos si es necesario
                if child_delay > 1000:  # Asumir que está en milisegundos
                    child_delay = child_delay // 1000
                
                # Usar nombre descriptivo para el job hijo
                child_job_name = child_opts.get('jobId') or f"flow_{parent_name}_{child_name}_child_{i}"
                
                child_id = await bullmq_sender_async(
                    worker=child_queue,
                    priority=child_priority,
                    delay_sec=child_delay,
                    message=child_message,
                    redis_url=redis_url,
                    job_id=child_job_name
                )
                
                child_result = {
                    "child_index": i,
                    "child_name": child_name,
                    "child_job_id": child_id,
                    "child_queue": child_queue,
                    "child_priority": child_priority,
                    "child_delay": child_delay
                }
                
                children_results.append(child_result)
                
                logger.info(f"Child job {i} created: {child_id} in queue '{child_queue}' (name: {child_name})")
                
            except Exception as e:
                logger.error(f"Error creating child job {i}: {str(e)}")
                # Continuar con los otros hijos
                children_results.append({
                    "child_index": i,
                    "child_name": child_config.get('name', f"child_{i}"),
                    "error": str(e),
                    "status": "failed"
                })
        
        # Resultado final del flow
        flow_result = {
            "status": "success",
            "flow_id": flow_id,
            "flow_name": parent_name,
            "flow_timestamp": flow_timestamp,
            "parent_job": {
                "job_id": parent_id,
                "queue": parent_queue,
                "name": parent_name,
                "priority": parent_priority,
                "delay": parent_delay
            },
            "children": children_results,
            "children_count": len(children_results),
            "children_success": len([c for c in children_results if "error" not in c]),
            "children_failed": len([c for c in children_results if "error" in c])
        }
        
        logger.info(f"Flow '{parent_name}' created successfully: {flow_result['children_success']}/{flow_result['children_count']} children created")
        
        return flow_result
        
    except Exception as e:
        logger.error(f"Error creating flow: {str(e)}")
        return {
            "status": "error",
            "flow_id": flow_id,
            "error": str(e),
            "flow_timestamp": flow_timestamp
        }

def bullmq_flow_status(flow_id: str, redis_url: str = None) -> Dict:
    """
    Función para consultar el estado de un flow por su ID.
    
    Args:
        flow_id: ID del flow a consultar
        redis_url: URL de Redis (opcional)
    
    Returns:
        Dict: Estado del flow con información de jobs padre e hijos
    """
    return asyncio.run(bullmq_flow_status_async(flow_id, redis_url))

async def bullmq_flow_status_async(flow_id: str, redis_url: str = None) -> Dict:
    """
    Versión asíncrona de bullmq_flow_status.
    
    Args:
        flow_id: ID del flow a consultar
        redis_url: URL de Redis (opcional)
    
    Returns:
        Dict: Estado del flow con información de jobs padre e hijos
    """
    if redis_url is None:
        redis_url = os.environ.get('REDIS_HOST', 'redis://192.168.1.163:6379')
    
    try:
        # Esta es una implementación básica - en una implementación más avanzada
        # podrías buscar en todas las colas conocidas o usar una cola de metadata
        logger.info(f"Checking status for flow: {flow_id}")
        
        # Por ahora retornamos información básica
        # En una implementación completa, consultarías Redis directamente
        return {
            "status": "not_implemented",
            "flow_id": flow_id,
            "message": "Flow status checking not fully implemented yet",
            "suggestion": "Use BullMQ dashboard to monitor flow progress"
        }
        
    except Exception as e:
        logger.error(f"Error checking flow status: {str(e)}")
        return {
            "status": "error",
            "flow_id": flow_id,
            "error": str(e)
        }

# Función de ejemplo/testing
if __name__ == "__main__":
    # Ejemplo de configuración de flow similar al JavaScript
    flow_config = {
        "name": "parent-job",
        "queueName": "parents",
        "data": {"message": "This is the parent job", "timestamp": datetime.now().isoformat()},
        "opts": {"priority": 8},
        "children": [
            {
                "name": "child-1",
                "queueName": "children",
                "data": {"x": 1, "task": "process_data"},
                "opts": {
                    "delay": 10000,  # 10 segundos en milisegundos
                    "priority": 7
                }
            },
            {
                "name": "child-2", 
                "queueName": "children",
                "data": {"x": 2, "task": "process_data"},
                "opts": {"priority": 6}
            },
            {
                "name": "child-3",
                "queueName": "special_children",
                "data": {"x": 3, "task": "special_process", "config": {"timeout": 30}},
                "opts": {"priority": 9}
            }
        ]
    }
    
    try:
        print("=== BullMQ Flow Example ===")
        print(f"Creating flow with {len(flow_config['children'])} children...")
        
        result = bullmq_flow(flow_config)
        
        print(f"\nFlow Result:")
        print(f"Status: {result['status']}")
        print(f"Flow ID: {result.get('flow_id', 'N/A')}")
        print(f"Parent Job ID: {result.get('parent_job', {}).get('job_id', 'N/A')}")
        print(f"Children Created: {result.get('children_success', 0)}/{result.get('children_count', 0)}")
        
        if result.get('children'):
            print("\nChildren Details:")
            for child in result['children']:
                if 'error' not in child:
                    print(f"  - {child['child_name']}: {child['child_job_id']} (queue: {child['child_queue']}, delay: {child['child_delay']}s)")
                else:
                    print(f"  - {child['child_name']}: ERROR - {child['error']}")
        
        print("\n✅ Flow created successfully!")
        print("Check your BullMQ dashboard to see the jobs in different queues.")
        
    except Exception as e:
        print(f"❌ Error creating flow: {e}")