#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script para reorganizar las colas y sus miembros
Fecha: 31 de Julio de 2025

Objetivos:
1. Limpiar queue_members obsoletos
2. Asignar agentes a las colas correctas (tarot, info, erotico)
3. Configurar interfaces correctamente para teléfonos geográficos
"""

import mysql.connector
import sys
import logging
from datetime import datetime

# Configuración de logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# Configuración de base de datos
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': 'asterisk1234',
    'database': 'asterisk'
}

def get_db_connection():
    """Obtiene conexión a la base de datos"""
    try:
        return mysql.connector.connect(**DB_CONFIG)
    except Exception as e:
        logger.error(f"Error conectando a BD: {e}")
        sys.exit(1)

def analyze_current_state():
    """Analiza el estado actual de las colas"""
    conn = get_db_connection()
    cursor = conn.cursor()
    
    logger.info("=== ANÁLISIS DEL ESTADO ACTUAL ===")
    
    # 1. Colas con miembros
    cursor.execute("""
        SELECT queue_name, COUNT(*) as members 
        FROM queue_members 
        GROUP BY queue_name 
        ORDER BY members DESC
    """)
    
    logger.info("\nColas actuales con miembros:")
    for queue, count in cursor.fetchall():
        logger.info(f"  Cola {queue}: {count} miembros")
    
    # 2. Agentes con teléfonos geográficos
    cursor.execute("""
        SELECT usuario, nombre, telefono 
        FROM agentes 
        WHERE telefono IS NOT NULL 
        AND telefono != ''
        AND activo = 1
    """)
    
    logger.info("\nAgentes con teléfonos geográficos:")
    agents_with_phones = cursor.fetchall()
    for agent in agents_with_phones[:10]:  # Mostrar solo los primeros 10
        logger.info(f"  {agent[0]} - {agent[1]} - Tel: {agent[2]}")
    
    cursor.close()
    conn.close()
    
    return agents_with_phones

def clean_queue_members():
    """Limpia queue_members obsoletos"""
    conn = get_db_connection()
    cursor = conn.cursor()
    
    logger.info("\n=== LIMPIEZA DE QUEUE_MEMBERS ===")
    
    # Backup primero
    backup_file = f"/tmp/queue_members_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.sql"
    cursor.execute("SELECT * FROM queue_members")
    members = cursor.fetchall()
    
    with open(backup_file, 'w') as f:
        f.write("-- Backup de queue_members\n")
        for member in members:
            f.write(f"INSERT INTO queue_members VALUES {member};\n")
    
    logger.info(f"Backup guardado en: {backup_file}")
    
    # Limpiar todas las entradas actuales
    cursor.execute("DELETE FROM queue_members")
    deleted = cursor.rowcount
    conn.commit()
    
    logger.info(f"Eliminados {deleted} registros de queue_members")
    
    cursor.close()
    conn.close()

def configure_agent_routing():
    """Configura el enrutamiento correcto para agentes"""
    conn = get_db_connection()
    cursor = conn.cursor()
    
    logger.info("\n=== CONFIGURACIÓN DE ENRUTAMIENTO DE AGENTES ===")
    
    # Obtener todos los agentes activos
    cursor.execute("""
        SELECT usuario, nombre, telefono, estado_login
        FROM agentes
        WHERE activo = 1
        ORDER BY usuario
    """)
    
    agents = cursor.fetchall()
    
    # Clasificar agentes por tipo
    tarot_agents = []
    info_agents = []
    erotico_agents = []
    
    for agent in agents:
        codigo = agent[0]
        nombre = agent[1]
        telefono = agent[2]
        
        # Clasificación por código/nombre (ajustar según necesidades reales)
        if codigo.startswith('3') or codigo.startswith('5'):
            tarot_agents.append((codigo, nombre, telefono))
        elif 'info' in nombre.lower() or codigo in ['351', '352', '353', '354']:
            info_agents.append((codigo, nombre, telefono))
        elif 'ero' in nombre.lower() or codigo.startswith('4'):
            erotico_agents.append((codigo, nombre, telefono))
        else:
            # Por defecto a tarot
            tarot_agents.append((codigo, nombre, telefono))
    
    logger.info(f"Agentes clasificados:")
    logger.info(f"  Tarot: {len(tarot_agents)}")
    logger.info(f"  Info: {len(info_agents)}")
    logger.info(f"  Erótico: {len(erotico_agents)}")
    
    # Insertar agentes en las colas correctas
    insert_count = 0
    
    # Cola tarot
    for agent in tarot_agents:
        codigo, nombre, telefono = agent
        if telefono and telefono.strip():
            # Agente con teléfono geográfico - usar Local channel
            interface = f"Local/{codigo}@agents-out"
            state_interface = f"PJSIP/{codigo}"
        else:
            # Agente local - usar PJSIP directo
            interface = f"PJSIP/{codigo}"
            state_interface = f"PJSIP/{codigo}"
        
        cursor.execute("""
            INSERT INTO queue_members 
            (queue_name, interface, membername, state_interface, penalty, paused)
            VALUES (%s, %s, %s, %s, 0, 0)
        """, ('tarot', interface, codigo, state_interface))
        insert_count += 1
    
    # Cola info
    for agent in info_agents:
        codigo, nombre, telefono = agent
        if telefono and telefono.strip():
            interface = f"Local/{codigo}@agents-out"
            state_interface = f"PJSIP/{codigo}"
        else:
            interface = f"PJSIP/{codigo}"
            state_interface = f"PJSIP/{codigo}"
        
        cursor.execute("""
            INSERT INTO queue_members 
            (queue_name, interface, membername, state_interface, penalty, paused)
            VALUES (%s, %s, %s, %s, 0, 0)
        """, ('info', interface, codigo, state_interface))
        insert_count += 1
    
    # Cola erotico
    for agent in erotico_agents:
        codigo, nombre, telefono = agent
        if telefono and telefono.strip():
            interface = f"Local/{codigo}@agents-out"
            state_interface = f"PJSIP/{codigo}"
        else:
            interface = f"PJSIP/{codigo}"
            state_interface = f"PJSIP/{codigo}"
        
        cursor.execute("""
            INSERT INTO queue_members 
            (queue_name, interface, membername, state_interface, penalty, paused)
            VALUES (%s, %s, %s, %s, 0, 0)
        """, ('erotico', interface, codigo, state_interface))
        insert_count += 1
    
    conn.commit()
    logger.info(f"\nInsertados {insert_count} miembros en las colas")
    
    cursor.close()
    conn.close()

def create_agent_routing_context():
    """Crea el contexto para enrutar llamadas a agentes con teléfonos geográficos"""
    
    context = """
; Contexto para enrutar llamadas a agentes con teléfonos geográficos
[agents-out]
; Este contexto maneja las llamadas a agentes que tienen teléfonos externos
; Formato: Local/CODIGO@agents-out donde CODIGO es el código del agente

; Patrón general para todos los agentes
exten => _X.,1,NoOp(Llamando a agente ${EXTEN})
 same => n,Set(AGENT_CODE=${EXTEN})
 same => n,Set(AGENT_PHONE=${ODBC_GET_AGENT_PHONE(${AGENT_CODE})})
 same => n,GotoIf($["${AGENT_PHONE}" = ""]?noagent)
 same => n,NoOp(Teléfono del agente: ${AGENT_PHONE})
 same => n,Set(CALLERID(name)=Llamada Entrante)
 same => n,Set(CALLERID(num)=${CALLERID(num)})
 same => n,Dial(PJSIP/${AGENT_PHONE}@switch,60,tT)
 same => n,Hangup()
 same => n(noagent),NoOp(Agente ${AGENT_CODE} no encontrado o sin teléfono)
 same => n,Congestion(5)
 same => n,Hangup()

; Para debug
exten => test,1,NoOp(Test del contexto agents-out)
 same => n,Playback(tt-monkeys)
 same => n,Hangup()
"""
    
    # Guardar en archivo
    with open('/tmp/agents_out_context.conf', 'w') as f:
        f.write(context)
    
    logger.info("\nContexto agents-out creado en: /tmp/agents_out_context.conf")
    logger.info("Agregar al final de /etc/asterisk/extensions.conf:")
    logger.info("#include \"/tmp/agents_out_context.conf\"")
    
    # También necesitamos crear la función ODBC
    odbc_func = """
[GET_AGENT_PHONE]
prefix=GET
dsn=asterisk
readsql=SELECT telefono FROM agentes WHERE usuario = '${ARG1}' AND activo = 1
"""
    
    with open('/tmp/func_odbc_agents.conf', 'w') as f:
        f.write(odbc_func)
    
    logger.info("\nFunción ODBC creada en: /tmp/func_odbc_agents.conf")
    logger.info("Copiar a /etc/asterisk/func_odbc.conf")

def verify_configuration():
    """Verifica la configuración final"""
    conn = get_db_connection()
    cursor = conn.cursor()
    
    logger.info("\n=== VERIFICACIÓN FINAL ===")
    
    # Verificar miembros en colas nombradas
    cursor.execute("""
        SELECT queue_name, COUNT(*) as members
        FROM queue_members
        WHERE queue_name IN ('tarot', 'info', 'erotico', 'redireccion')
        GROUP BY queue_name
    """)
    
    logger.info("\nMiembros en colas nombradas:")
    for queue, count in cursor.fetchall():
        logger.info(f"  {queue}: {count} miembros")
    
    # Verificar agentes con Local channel
    cursor.execute("""
        SELECT queue_name, interface, membername
        FROM queue_members
        WHERE interface LIKE 'Local/%'
        LIMIT 10
    """)
    
    logger.info("\nEjemplos de agentes con enrutamiento externo:")
    for row in cursor.fetchall():
        logger.info(f"  Cola: {row[0]}, Interface: {row[1]}, Agente: {row[2]}")
    
    cursor.close()
    conn.close()

def main():
    """Función principal"""
    logger.info("=== INICIANDO REORGANIZACIÓN DE COLAS ===")
    logger.info(f"Fecha: {datetime.now()}")
    
    # 1. Analizar estado actual
    agents_with_phones = analyze_current_state()
    
    # 2. Preguntar confirmación
    print("\n¿Desea proceder con la reorganización? (s/n): ", end='')
    response = input().strip().lower()
    
    if response != 's':
        logger.info("Operación cancelada por el usuario")
        return
    
    # 3. Limpiar queue_members
    clean_queue_members()
    
    # 4. Configurar nuevo enrutamiento
    configure_agent_routing()
    
    # 5. Crear contexto de enrutamiento
    create_agent_routing_context()
    
    # 6. Verificar configuración
    verify_configuration()
    
    logger.info("\n=== REORGANIZACIÓN COMPLETADA ===")
    logger.info("Próximos pasos:")
    logger.info("1. Revisar y ajustar la clasificación de agentes por cola")
    logger.info("2. Agregar el contexto agents-out a extensions.conf")
    logger.info("3. Agregar la función ODBC a func_odbc.conf")
    logger.info("4. Recargar Asterisk: asterisk -rx 'core reload'")

if __name__ == "__main__":
    main()