import logging
import sys
import traceback

sys.path.append('/var/www/html/config')
from cnxpdo import get_connection
from datetime import datetime


def list_prospectos(data: dict):
    conexion = None
    cursor = None

    try:
        # 🔧 VALIDACIÓN Y DEBUG DE PARÁMETROS
        page = max(1, int(data.get('page', 1)))
        page_size = min(100, max(1, int(data.get('pageSize', 5))))
        offset = (page - 1) * page_size

        conexion = get_connection()
        if conexion is None:
            raise Exception("Error de conexión a la base de datos")

        cursor = conexion.cursor(dictionary=True)
        
        # 🔧 OBTENER TOTAL DE REGISTROS
        count_query = "SELECT COUNT(*) AS total FROM union_contactos_personas"
        cursor.execute(count_query)
        total_records = cursor.fetchone()['total']
        
        # 🔧 CALCULAR PÁGINAS TOTALES - FÓRMULA MEJORADA
        if total_records == 0:
            total_pages = 1
            # Si no hay datos, devolver página 1 vacía
            response = {
                "success": True,
                "message": "No se encontraron registros",
                "data": [],
                "totalRecords": 0,
                "totalPages": 1,
                "currentPage": 1,
                "pageSize": page_size,
                "hasNextPage": False,
                "hasPrevPage": False
            }
            return response
        else:
            total_pages = (total_records + page_size - 1) // page_size
        
        # 🔧 VALIDAR Y AJUSTAR LA PÁGINA - CORREGIDO
        original_page = page
        if page > total_pages:
            page = total_pages
            offset = (page - 1) * page_size
        
        # Validar que el offset no sea negativo
        if offset < 0:
            offset = 0
            page = 1

        # 🔧 CONSULTA CON VALIDACIÓN DE OFFSET Y NUEVOS CAMPOS
        query = """
            SELECT 
                uc.id, 
                fecha_registro, 
                uc.nombre_embajador, 
                uc.nombres, 
                uc.apellidos, 
                uc.tipo_documento, 
                uc.documento,
                uc.correos, 
                uc.telefono, 
                uc.pais, 
                uc.departamento, 
                uc.ciudad, 
                uc.localidad, 
                uc.barrio,
                uc.direccion, 
                uc.fecha_cumpleanos, 
                uc.genero, 
                uc.tipo_sangre, 
                uc.recomendado,
                uc.nombre_recomendador, 
                uc.nombre_embajador, 
                uc.grupo_wp, 
                uc.grupo_wp1, 
                uc.como_ayudar, 
                uc.pasion,
                uc.intereses, 
                uc.autorizacion, 
                uc.estado_etapa, 
                uc.id_origen_datos, 
                uc.origen_datos, 
                uc.fecha_registro_contacto,
                DATEDIFF(CURDATE(), lpc_ultimo.ultima_fecha_hora) AS id_notificacion_contacto,
                uca.assignment_id,
                uca.assigned_user_id,
                uca.caller_user_id,
                uca.coordinator_user_id,
                uca.administrator_user_id
            FROM union_contactos_personas uc
            INNER JOIN (
                SELECT 
                    id_contacto,
                    MAX(fecha_hora) as ultima_fecha_hora
                FROM logs_primer_contacto 
                GROUP BY id_contacto
            ) lpc_ultimo ON uc.id = lpc_ultimo.id_contacto
            LEFT JOIN user_contact_assignments uca ON uc.id = uca.contacted_person_id
            ORDER BY uc.id DESC
            LIMIT %s OFFSET %s
        """
        
        cursor.execute(query, (page_size, offset))
        contactos_data = cursor.fetchall()

        # 🔧 FORMATEAR DATOS
        for contacto in contactos_data:
            # Formatear fechas
            for campo_fecha in ['fecha_registro', 'fecha_registro_contacto', 'fecha_cumpleanos']:
                if contacto.get(campo_fecha) and hasattr(contacto[campo_fecha], 'strftime'):
                    formato = '%Y-%m-%d %H:%M:%S' if campo_fecha == 'fecha_registro_contacto' else '%Y-%m-%d'
                    contacto[campo_fecha] = contacto[campo_fecha].strftime(formato)

            # 🆕 LIMPIAR ORIGEN_DATOS - NUEVA FUNCIONALIDAD
            if contacto.get('origen_datos'):
                origen_raw = contacto['origen_datos']
                # Quitar underscores del inicio y final
                origen_limpio = origen_raw.strip('_')
                # Convertir underscores internos a espacios
                origen_limpio = origen_limpio.replace('_', ' ')
                # Trim final de espacios
                contacto['origen_datos'] = origen_limpio.strip()
                
                # 🔧 DEBUG - Log de limpieza (opcional, quitar en producción)
                if origen_raw != contacto['origen_datos']:
                    logging.debug(f"🧹 Origen limpiado: '{origen_raw}' → '{contacto['origen_datos']}'")

            # Limpiar estado_etapa
            contacto['estado_etapa'] = int(contacto.get('estado_etapa') or 0)

            # 🆕 LIMPIAR CAMPOS DE ASIGNACIÓN - CONVERTIR A INT O NULL
            campos_asignacion = ['assignment_id', 'assigned_user_id', 'caller_user_id', 
                                'coordinator_user_id', 'administrator_user_id']
            
            for campo in campos_asignacion:
                valor = contacto.get(campo)
                if valor is None or valor == '':
                    contacto[campo] = None
                else:
                    try:
                        contacto[campo] = int(valor)
                    except (ValueError, TypeError):
                        contacto[campo] = None

            # Limpiar valores NULL para campos de texto
            for key, value in contacto.items():
                # No procesar los campos de asignación que ya fueron procesados
                if key in campos_asignacion:
                    continue
                    
                if value is None:
                    contacto[key] = ''
                elif isinstance(value, str):
                    contacto[key] = value.strip()

        # 🔧 CALCULAR METADATOS DE PAGINACIÓN - LÓGICA CORREGIDA
        registros_devueltos = len(contactos_data)
        
        # Calcular correctamente si hay página siguiente y anterior
        has_next_page = page < total_pages
        has_prev_page = page > 1
        
        # Validar consistencia: si estamos en la última página y no hay registros,
        # algo está mal con la paginación
        if page == total_pages and registros_devueltos == 0 and total_records > 0:
            logging.warning(f"⚠️ Inconsistencia detectada: página {page} sin registros pero total_records={total_records}")
            # Recalcular desde la página anterior
            page = max(1, total_pages - 1)
            offset = (page - 1) * page_size
            cursor.execute(query, (page_size, offset))
            contactos_data = cursor.fetchall()
            registros_devueltos = len(contactos_data)
            has_next_page = page < total_pages
            has_prev_page = page > 1

        # Mensaje informativo mejorado
        if registros_devueltos == 0:
            message = f"No hay registros en la página {page}"
        else:
            inicio = offset + 1
            fin = offset + registros_devueltos
            message = f"Página {page} de {total_pages} - Registros {inicio}-{fin} de {total_records}"

        response = {
            "success": True,
            "message": message,
            "data": contactos_data,
            "totalRecords": total_records,
            "totalPages": total_pages,
            "currentPage": page,
            "pageSize": page_size,
            "hasNextPage": has_next_page,
            "hasPrevPage": has_prev_page,
            # Agregar información adicional para debugging
            "debug": {
                "offset": offset,
                "requestedPage": original_page,
                "actualPage": page,
                "recordsInPage": registros_devueltos
            }
        }
        
        return response

    except ValueError as ve:
        logging.error(f"❌ Error de validación: {str(ve)}")
        return {
            "success": False,
            "message": "Parámetros inválidos",
            "data": [],
            "totalRecords": 0,
            "totalPages": 1,
            "currentPage": 1,
            "pageSize": 5,
            "hasNextPage": False,
            "hasPrevPage": False,
            "error": str(ve)
        }
    
    except Exception as e:
        return {
            'success': 0,
            'message': f'Error: {str(e)}',
            
        }
    
    finally:
        # Asegurarnos de cerrar la conexión y el cursor
        if cursor:
            cursor.close()
        if conexion:
            conexion.close()

            
def insertarRecordatorioFidelizacion(data):
    conexionBD = get_connection()
    if conexionBD is None:
        return {"success": 0, "message": "Error de conexión"}

    try:
        cursor = conexionBD.cursor()
        query = """
            INSERT INTO recordatorios (id_contacto_union, id_agente_creador, asunto, descripcion, fecha_hora, id_agente_asignado, id_etapa, fecha_hora_registro)
            VALUES (%s, %s, %s, %s, %s, %s, %s, now())
        """
        cursor.execute(query, (
            data['id_contacto_union'], data['id_agente_creador'], data['asunto'], data['descripcion'], data['fecha_hora'], data['id_agente_asignado'], data['id_etapa']
        ))
        conexionBD.commit()
  
        cursor.close()
        conexionBD.close()

        return {
            "success": 1,
            "message": "Recordatorio insertado",
            "data": data
        }

    except Exception as e:
        conexionBD.close()
        return {
            "success": 0,
            "message": f"Error: {str(e)}"
        }



def insertarContacto(data):
    try:
        conexionBD = get_connection()
        if conexionBD is None:
            return {"success": 0, "message": "Error de conexión"}
        
        # Obtener los datos desde el input (con valores opcionales manejados por el modelo)
        id_persona = data.get("id")
        fecha_registro = data.get("fecha_registro")
        id_embajador = data.get("id_embajador")
        nombre_embajador = data.get("nombre_embajador")
        nombres_completos = data.get("nombres_completos")
        nombres = data.get("nombres")
        apellidos = data.get("apellidos")
        tipo_documento = data.get("tipo_documento")
        documento = data.get("documento")
        correos = data.get("correos")
        telefono = data.get("telefono")
        pais = data.get("pais")
        departamento = data.get("departamento")
        ciudad = data.get("ciudad")
        localidad = data.get("localidad")
        barrio = data.get("barrio")
        direccion = data.get("direccion")
        fecha_cumpleanos = data.get("fecha_cumpleanos")
        genero = data.get("genero")
        tipo_sangre = data.get("tipo_sangre")
        recomendado = data.get("recomendado")
        nombre_recomendador = data.get("nombre_recomendador")
        grupo_wp = data.get("grupo_wp")
        grupo_wp1 = data.get("grupo_wp1")
        como_ayudar = data.get("como_ayudar")
        pasion = data.get("pasion")
        intereses = data.get("intereses")
        autorizacion = data.get("autorizacion")
        estado_etapa = data.get("estado_etapa")
        origen_datos = data.get("nombreTabla")
        fecha_registro_contacto = data.get("fecha_registro_contacto")
        tiempo_primer_contacto = data.get("tiempo_primer_contacto")
        noQuisoParticipar = data.get("noQuisoParticipar")

        if noQuisoParticipar:
            update_query_descartado = f"""
            UPDATE {origen_datos} 
            SET estado_etapa = %s, fecha_estado = NOW() 
            WHERE id = %s
            """
        
            cursor = conexionBD.cursor()
            cursor.execute(update_query_descartado, (5, id_persona))  # Estado 5: "Descartado"
            conexionBD.commit()

            # Insertar log de evento con estado 4
            evento = '4'
            leido = '0'
            id_contacto = '0'
            insert_log_query = '''
            INSERT INTO logs_primer_contacto (id_usuario, origen_datos, id_contacto_origen, id_contacto, id_evento, leido)
            VALUES (%s, %s, %s, %s, %s, %s)
            '''
            cursor.execute(insert_log_query, (id_embajador, origen_datos, id_persona, id_contacto, evento, leido))
            conexionBD.commit()

            # Cerrar la conexión y retornar
            cursor.close()
            conexionBD.close()

            return {"success": 1, "message": "Se pasó a estado descartado y se registró el log."}

        # Validar y separar nombres y apellidos si nombres_completos tiene valor
        if not nombres and not apellidos and nombres_completos:
            nombres_completos_split = nombres_completos.strip().split()
            if len(nombres_completos_split) == 1:
                nombres = nombres_completos_split[0]
                apellidos = ''
            elif len(nombres_completos_split) == 2:
                nombres, apellidos = nombres_completos_split
            elif len(nombres_completos_split) > 2:
                nombres = ' '.join(nombres_completos_split[:-1])
                apellidos = nombres_completos_split[-1]

        # Inserción en la base de datos
        query2 = """
            INSERT INTO 
                union_contactos_personas(
                    fecha_registro,
                    nombre_embajador,
                    nombres,
                    apellidos,
                    tipo_documento,
                    documento,
                    correos,
                    telefono,
                    pais,
                    departamento,
                    ciudad,
                    localidad,
                    barrio,
                    direccion,
                    fecha_cumpleanos,
                    genero,
                    tipo_sangre,
                    recomendado,
                    nombre_recomendador,
                    grupo_wp,
                    grupo_wp1,
                    como_ayudar,
                    pasion,
                    intereses,
                    autorizacion,
                    estado_etapa,
                    id_origen_datos,
                    origen_datos,
                    fecha_registro_contacto,
                    tiempo_primer_contacto
                ) 
            VALUES (
                %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
            )
        """
        
        cursor = conexionBD.cursor()
        cursor.execute(query2, (
            fecha_registro, nombre_embajador, nombres, apellidos, tipo_documento, documento, correos, telefono, pais, 
            departamento, ciudad, localidad, barrio, direccion, fecha_cumpleanos, genero, tipo_sangre, recomendado, 
            nombre_recomendador, grupo_wp, grupo_wp1, como_ayudar, pasion, intereses, autorizacion, 
            estado_etapa, id_persona, origen_datos, fecha_registro_contacto, tiempo_primer_contacto
        ))
        
        # Obtener el id del contacto recién insertado
        id_contacto = cursor.lastrowid

        # Agregar la consulta UPDATE después de la inserción exitosa
        update_query = f"""
            UPDATE {origen_datos} 
            SET estado_etapa = %s, fecha_estado = NOW() 
            WHERE id = %s
        """
        
        cursor.execute(update_query, (estado_etapa, id_persona))
        
        # Insertar log de evento
        evento = '1'
        leido = '0'
        insert_log_query = '''
            INSERT INTO logs_primer_contacto (id_usuario, origen_datos, id_contacto_origen, id_contacto, id_evento, leido)
            VALUES (%s, %s, %s, %s, %s, %s)
        '''
        cursor.execute(insert_log_query, (id_embajador, origen_datos, id_persona, id_contacto, evento, leido))
        # Commit para confirmar la inserción
        conexionBD.commit()

        # Agregar el id_contacto al objeto data
        data["id_contacto"] = id_contacto

        cursor.close()
        conexionBD.close()

        return {
            "success": 1, 
            "message": "Datos insertados correctamente", 
            "data": data
        }
    
    except Exception as e:
        return {"success": 0, "message": f"Error al insertar datos: {str(e)}"}



def actualizar_contacto(id_voluntario, data):
    conexionBD = get_connection()
    cursor = None 
    
    if conexionBD is None:
        return {"success": False, "message": "Error de conexión a la base de datos"}

    try:
        fecha_registro = data.get("fecha_registro") or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        nombre_embajador = data.get("nombre_embajador") or 'No embajador asignado'
        nombres = data.get("nombres", None)
        apellidos = data.get("apellidos", None)
        tipo_documento = data.get("tipo_documento", None)
        documento = data.get("documento", None)
        correos = data.get("correos", None)
        telefono = data.get("telefono", None)
        pais = data.get("pais", None)
        departamento = data.get("departamento", None)
        ciudad = data.get("ciudad", None)
        localidad = data.get("localidad", None)
        barrio = data.get("barrio", None)
        direccion = data.get("direccion", None)
        fecha_cumpleanos = data.get("fecha_cumpleanos", None)
        genero = data.get("genero", None) 
        tipo_sangre = data.get("tipo_sangre", None)
        recomendado = data.get("recomendado", None) or 'No'
        nombre_recomendador = data.get("nombre_recomendador", None) or 'No recomendado'
        grupo_wp = data.get("grupo_wp", None)
        grupo_wp1 = data.get("grupo_wp1", None)
        como_ayudar = data.get("como_ayudar", None)
        pasion = data.get("pasion", None)
        intereses = data.get("intereses", None)
        autorizacion = data.get("autorizacion", None)
        estado_etapa = data.get("estado_etapa")
        if estado_etapa is None:
            estado_etapa = 1
        origen_datos = data.get("origen_datos") or "Sin origen"
        tiempo_primer_contacto = data.get("tiempo_primer_contacto") or "00:00:00"
        fecha_registro_contacto = data.get("fecha_registro_contacto") or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        
        cursor = conexionBD.cursor(dictionary=True)

        query = None 
        params = []   

        query = """
                UPDATE union_contactos_personas
            SET tipo_documento = %s, documento = %s, nombres = %s, apellidos = %s, correos = %s, 
                telefono = %s, pais = %s, departamento = %s, ciudad = %s, direccion = %s, 
                genero = %s, recomendado = %s, nombre_recomendador = %s, grupo_wp = %s, 
                grupo_wp1 = %s, como_ayudar = %s, pasion = %s, estado_etapa = %s,
                nombre_embajador = %s, localidad = %s, barrio = %s, fecha_cumpleanos = %s,
                tipo_sangre = %s, intereses = %s, autorizacion = %s, origen_datos = %s, tiempo_primer_contacto = %s, fecha_registro_contacto = %s, fecha_registro = %s
            WHERE id = %s
            """
        params = [tipo_documento, documento, nombres, apellidos, correos, telefono,
            pais, departamento, ciudad, direccion, genero, recomendado,
            nombre_recomendador, grupo_wp, grupo_wp1, como_ayudar, pasion, estado_etapa,
            nombre_embajador, localidad, barrio, fecha_cumpleanos,
            tipo_sangre, intereses, autorizacion, origen_datos, tiempo_primer_contacto, fecha_registro_contacto, fecha_registro, id_voluntario]

            
        if query is None:
            return {"success": False, "message": "Tabla no válida especificada en la solicitud"}

        
        cursor.execute(query, params)

        conexionBD.commit()

        query_select = "SELECT * FROM union_contactos_personas WHERE id = %s"
        cursor.execute(query_select, (id_voluntario,))
        voluntario_actualizado = cursor.fetchone()

        cursor.close()
        conexionBD.close()

        return {"success": True, "message": "Voluntario actualizado", "data": voluntario_actualizado}
    
    except Exception as e:
        logging.error("Error al actualizar los datos: %s", str(e))
        logging.error(traceback.format_exc())
        return {
            "success": False,
            "message": f"Error al actualizar los datos: {str(e)}",
            "trace": traceback.format_exc()
        }
    
    finally:
        if cursor:
            cursor.close()
        if conexionBD:
            conexionBD.close()


def obtener_recordatorios_por_contacto(id_contacto_union):
    """
    Obtiene todos los recordatorios de un contacto específico
    """
    conexion = None
    cursor = None
    
    try:
        conexion = get_connection()
        if conexion is None:
            return {"success": False, "message": "Error de conexión a la base de datos"}

        cursor = conexion.cursor(dictionary=True)
        
        # Consulta para obtener los recordatorios con información del agente asignado
        query = """
            SELECT 
                r.id,
                r.asunto,
                r.descripcion,
                r.fecha_hora,
                r.fecha_hora_registro,
                r.id_agente_creador,
                r.id_agente_asignado,
                r.id_etapa,
                e.nombres as agente_nombres,
                e.apellidos as agente_apellidos,
                e.correo_corporativo as agente_correo
            FROM recordatorios r
            LEFT JOIN empleados e ON r.id_agente_asignado = e.id
            WHERE r.id_contacto_union = %s
            ORDER BY r.fecha_hora DESC
        """
        
        cursor.execute(query, (id_contacto_union,))
        recordatorios = cursor.fetchall()
        
        # Formatear las fechas para mejor visualización
        for recordatorio in recordatorios:
            if recordatorio.get('fecha_hora'):
                recordatorio['fecha_hora'] = recordatorio['fecha_hora'].strftime('%Y-%m-%d %H:%M:%S')
            if recordatorio.get('fecha_hora_registro'):
                recordatorio['fecha_hora_registro'] = recordatorio['fecha_hora_registro'].strftime('%Y-%m-%d %H:%M:%S')
            
            # Combinar nombre completo del agente
            if recordatorio.get('agente_nombres') and recordatorio.get('agente_apellidos'):
                recordatorio['agente_completo'] = f"{recordatorio['agente_nombres']} {recordatorio['agente_apellidos']}"
            else:
                recordatorio['agente_completo'] = "Sin asignar"

        return {
            "success": True,
            "message": f"Se encontraron {len(recordatorios)} recordatorios",
            "data": recordatorios
        }

    except Exception as e:
        logging.error(f"Error al obtener recordatorios: {str(e)}")
        return {
            "success": False,
            "message": f"Error al obtener recordatorios: {str(e)}",
            "data": []
        }
    
    finally:
        if cursor:
            cursor.close()
        if conexion:
            conexion.close()



def get_respuestas_primer_contacto(id_contacto: int):
    try:
        conexionBD = get_connection()
        if conexionBD is None:
            return {
                "success": 0,
                "message": "Error de conexión"
            }

        if not id_contacto:
            return {
                "success": 0,
                "message": "Falta el ID del contacto"
            }

        cursor = conexionBD.cursor(dictionary=True)
        query = """
            SELECT *
            FROM personas_contactos
            WHERE id_union_contactos_personas = %s  
        """
        cursor.execute(query, (id_contacto,))
        respuestas = cursor.fetchall()

        return {
            "success": 1,
            "message": "Respuestas obtenidas correctamente",
            "data": respuestas
        }

    except Exception as e:
        return {
            "success": 0,
            "message": f"Error: {str(e)}"
        }
    finally:
        if 'cursor' in locals():
            cursor.close()
        if 'conexionBD' in locals() and conexionBD:
            conexionBD.close()


def obtener_id_evento(descripcion_evento):
    try:
        conexionBD = get_connection()
        if conexionBD is None:
            return None

        cursor = conexionBD.cursor()
        query = "SELECT id FROM eventos WHERE descripcion = %s"
        cursor.execute(query, (descripcion_evento,))
        resultado = cursor.fetchone()
        
        cursor.close()
        conexionBD.close()
        
        return resultado[0] if resultado else None
        
    except Exception as e:
        logging.error(f"Error al obtener ID del evento: {str(e)}")
        return None

def obtener_id_evento_por_estado(estado):
    mapeo_estados = {
        1: 1,  
        2: 1, 
        3: 2,  
        4: 3, 
        5: 4 
    }
    
    return mapeo_estados.get(estado)

def insertar_log_evento(id_usuario, id_contacto_origen, id_contacto, id_evento, tabla_origen_bd, leido='0'):
    try:
        conexionBD = get_connection()
        if conexionBD is None:
            return False

        cursor = conexionBD.cursor()
        query = """
            INSERT INTO logs_primer_contacto (id_usuario, origen_datos, id_contacto_origen, id_contacto, id_evento, leido)
            VALUES (%s, %s, %s, %s, %s, %s)
        """
        cursor.execute(query, (id_usuario, tabla_origen_bd, id_contacto_origen, id_contacto, id_evento, leido))
        conexionBD.commit()
        
        cursor.close()
        conexionBD.close()
        
        return True
        
    except Exception as e:
        logging.error(f"Error al insertar log del evento: {str(e)}")
        return False

def actualizar_estado_etapa_contacto(id_contacto: int, nuevo_estado: int, id_usuario: int = None):
    conexion = None
    cursor = None
    
    try:
        conexion = get_connection()
        if conexion is None:
            return {"success": False, "message": "Error de conexión a la base de datos"}

        cursor = conexion.cursor(dictionary=True)
        
        # Obtener información del contacto
        query_origen = """
            SELECT id_origen_datos, origen_datos 
            FROM union_contactos_personas 
            WHERE id = %s
        """
        cursor.execute(query_origen, (id_contacto,))
        contacto_info = cursor.fetchone()
        
        if not contacto_info:
            return {"success": False, "message": "No se encontró el contacto"}
            
        id_origen = contacto_info['id_origen_datos']
        tabla_origen_raw = contacto_info['origen_datos']
        
        mapeo_tablas = {
            'inscripciones voluntarios': 'inscripciones_voluntarios',
            'prospectos manual': 'prospectos_manual', 
            'base datos 10k': 'base_datos_10k',
            'registros crm antiguo': 'registros_crm_antiguo',
            'inscripciones_voluntarios': 'inscripciones_voluntarios',
            'prospectos_manual': 'prospectos_manual',
            'base_datos_10k': 'base_datos_10k', 
            'registros_crm_antiguo': 'registros_crm_antiguo'
        }
        
        # Buscar la tabla real en el mapeo
        tabla_origen_bd = mapeo_tablas.get(tabla_origen_raw)
        
        if not tabla_origen_bd:
            logging.warning(f"Tabla no reconocida: '{tabla_origen_raw}'")
            # Solo actualizar union_contactos_personas
            query_union = "UPDATE union_contactos_personas SET estado_etapa = %s WHERE id = %s"
            cursor.execute(query_union, (nuevo_estado, id_contacto))
        else:
            # Actualizar ambas tablas
            query_union = "UPDATE union_contactos_personas SET estado_etapa = %s WHERE id = %s"
            cursor.execute(query_union, (nuevo_estado, id_contacto))
            filas_union = cursor.rowcount
            
            query_origen = f"UPDATE {tabla_origen_bd} SET estado_etapa = %s WHERE id = %s"
            cursor.execute(query_origen, (nuevo_estado, id_origen))
            filas_origen = cursor.rowcount
        
        # Commit de los cambios de estado
        conexion.commit()
        
        # NUEVO: Registrar log del evento si se proporciona id_usuario
        log_registrado = False
        if id_usuario:
            id_evento = obtener_id_evento_por_estado(nuevo_estado)
            if id_evento:
                log_registrado = insertar_log_evento(id_usuario, id_origen, id_contacto, id_evento, tabla_origen_bd)
                if log_registrado:
                    logging.info(f"Log del evento registrado: usuario {id_usuario}, contacto {id_contacto}, evento {id_evento}")
                else:
                    logging.warning(f"No se pudo registrar el log del evento para el contacto {id_contacto}")
            else:
                logging.warning(f"No se encontró el evento para el estado {nuevo_estado}")
        
        return {
            "success": True, 
            "message": f"Estado actualizado a {nuevo_estado}" + (" y log registrado" if log_registrado else ""),
            "id_contacto": id_contacto,
            "nuevo_estado": nuevo_estado,
            "tabla_origen_recibida": tabla_origen_raw,
            "tabla_origen_bd": tabla_origen_bd,
            "id_origen": id_origen,
            "log_registrado": log_registrado
        }
            
    except Exception as e:
        if conexion:
            conexion.rollback()
        logging.error(f"Error al actualizar estado_etapa: {str(e)}")
        return {
            "success": False,
            "message": f"Error al actualizar: {str(e)}"
        }
    
    finally:
        if cursor:
            cursor.close()
        if conexion:
            conexion.close()



def insertarTiempoSesion(data):
    try:
        # Obtener conexión a la base de datos
        conexionBD = get_connection()
        if conexionBD is None:
            return {"success": False , "message": "Error de conexión"}

        # Extraer datos del diccionario
        id_voluntario = data.get('id_voluntario')
        tiempo_primer_contacto = data.get('tiempo_primer_contacto')

        # Validar que los datos existan
        if not id_voluntario or not tiempo_primer_contacto:
            return {
                "success": False ,
                "message": "Faltan datos requeridos: id_voluntario y tiempo_primer_contacto"
            }

        # Query para actualizar el tiempo de sesión
        query = """
            UPDATE union_contactos_personas 
            SET tiempo_primer_contacto = %s
            WHERE id = %s
        """

        # Ejecutar la query
        cursor = conexionBD.cursor()
        cursor.execute(query, (tiempo_primer_contacto, id_voluntario))
        conexionBD.commit()

        # Verificar si se actualizó algún registro
        if cursor.rowcount == False :
            return {
                "success": False ,
                "message": f"No se encontró un registro con id {id_voluntario}"
            }

        return {
            "success": True,
            "message": "Tiempo de sesión actualizado correctamente",
            "data": {
                "id_voluntario": id_voluntario,
                "tiempo_primer_contacto": tiempo_primer_contacto,
                "affected_rows": cursor.rowcount
            }
        }

    except Exception as e:
        logging.error(f"Error en insertarTiempoSesion: {e}")
        return {
            "success": False ,
            "message": f"Error al actualizar el tiempo de sesión: {str(e)}"
        }
    finally:
        if 'cursor' in locals():
            cursor.close()
        if 'conexionBD' in locals() and conexionBD.is_connected():
            conexionBD.close()



def insert_user_assigned_contacted_person(data):
    conexionBD = get_connection()
    if conexionBD is None:
        return {
            'success': False,
            'message': 'Error de conexión'
        }

    try:
        
        query = """
            INSERT INTO 
                user_contact_assignments (
                    contacted_person_id, 
                    assigned_user_id, 
                    caller_user_id, 
                    coordinator_user_id, 
                    administrator_user_id
                )
            VALUES (%s, %s, %s, %s, %s)
        """
        
        cursor = conexionBD.cursor()
        cursor.execute(query, (
            data['contacted_person_id'],
            data['assigned_user_id'],
            data['caller_user_id'],
            data['coordinator_user_id'],
            data['administrator_user_id']
        ))
        
        conexionBD.commit()
        inserted_id = cursor.lastrowid
        
        cursor.close()
        conexionBD.close()

        return {
            'success': True,
            'message': 'Asignación insertada correctamente',
            'data': {'id': inserted_id}
        }

    except Exception as e:
        if 'cursor' in locals():
            cursor.close()
        if conexionBD:
            conexionBD.rollback()
            conexionBD.close()
        
        return {
            'success': False,
            'message': f"Error: {str(e)}"
        }


def update_user_assigned_contacted_person(data):
    conexionBD = get_connection()
    if conexionBD is None:
        return {
            'success': False,
            'message': 'Error de conexión'
        }

    try:
        query = """
            UPDATE user_contact_assignments
            SET 
                assigned_user_id = %s,
                caller_user_id = %s,
                coordinator_user_id = %s,
                administrator_user_id = %s,
                created_at = NOW()
            WHERE assignment_id = %s
        """
        
        cursor = conexionBD.cursor()
        cursor.execute(query, (
            data['assigned_user_id'],
            data['caller_user_id'],
            data['coordinator_user_id'],
            data['administrator_user_id'],
            data['assignment_id']
        ))
        
        rows_affected = cursor.rowcount
        conexionBD.commit()
        
        cursor.close()
        conexionBD.close()

        if rows_affected > 0:
            return {
                'success': True,
                'message': 'Asignación actualizada correctamente',
                'data': {
                    'assignment_id': data['assignment_id']
                }
            }
        else:
            return {
                'success': False,
                'message': 'No se encontró la asignación para actualizar'
            }

    except Exception as e:
        if 'cursor' in locals():
            cursor.close()
        if conexionBD:
            conexionBD.rollback()
            conexionBD.close()
        
        return {
            'success': False,
            'message': f"Error: {str(e)}"
        }
    

def delete_contact(id: int):
    """
    Elimina un contacto y todas sus referencias en las tablas relacionadas.
    """
    conexion = get_connection()
    if conexion is None:
        return {"success": False, "message": "Error de conexión a la base de datos"}

    cursor = None
    try:
        cursor = conexion.cursor(dictionary=True)

        # 1. Buscar en union_contactos_personas
        cursor.execute("SELECT id_origen_datos, origen_datos FROM union_contactos_personas WHERE id = %s", (id,))
        persona = cursor.fetchone()
        if not persona:
            return {"success": False, "message": "No se encontró el contacto en union_contactos_personas"}

        id_origen_datos = persona['id_origen_datos']
        origen_datos = persona['origen_datos']

        # 2. Buscar y eliminar en la tabla de origen si existe
        tabla_origen = origen_datos
        tablas_validas = [
            "inscripciones_voluntarios",
            "base_datos_10k",
            "registros_crm_antiguo",
            "prospectos_manual"
        ]
        if tabla_origen and id_origen_datos:
            # Normalizar el nombre de la tabla de origen para que tenga guion al piso
            tabla_origen = tabla_origen.strip().replace(" ", "_")
            # Si no tiene guion al piso y coincide con alguna tabla válida, lo agregamos
            if tabla_origen not in tablas_validas:
                for nombre in tablas_validas:
                    if tabla_origen.replace("_", "") == nombre.replace("_", ""):
                        tabla_origen = nombre
                        break
        if tabla_origen in tablas_validas:
            cursor.execute(f"DELETE FROM {tabla_origen} WHERE id = %s", (id_origen_datos,))
            print(f"DEBUG - Eliminado de {tabla_origen}: id {id_origen_datos}")
        else:
            print(f"DEBUG - Tabla no válida, no se elimina: '{tabla_origen}'")

        # 3. Eliminar en personas_contactos
        cursor.execute("DELETE FROM personas_contactos WHERE id_union_contactos_personas = %s", (id,))

        # 4. Eliminar en recordatorios
        cursor.execute("DELETE FROM recordatorios WHERE id_contacto_union = %s", (id,))

        # 5. Eliminar en logs_primer_contacto
        cursor.execute("DELETE FROM logs_primer_contacto WHERE id_contacto = %s", (id,))
        # 5b. Eliminar en logs_primer_contacto (por id_contacto_origen = id_origen_datos)
        if id_origen_datos:
            cursor.execute("DELETE FROM logs_primer_contacto WHERE origen_datos = %s AND id_contacto_origen = %s", (origen_datos, id_origen_datos))

        # 6. Eliminar en user_contact_assignments
        cursor.execute("DELETE FROM user_contact_assignments WHERE contacted_person_id = %s", (id,))

        # 7. Eliminar en notas_contacto (por id_contacto_union)
        cursor.execute("DELETE FROM notas_contacto WHERE id_contacto_union = %s", (id,))
        # 7b. Eliminar en notas_contacto (por id_contacto_origen = id_origen_datos)
        if id_origen_datos:
            cursor.execute("DELETE FROM notas_contacto WHERE origen_datos = %s AND id_contacto_origen = %s", (origen_datos, id_origen_datos))

        # 8. Finalmente, eliminar en union_contactos_personas
        cursor.execute("DELETE FROM union_contactos_personas WHERE id = %s", (id,))

        conexion.commit()
        return {"success": True, "message": "Contacto y todas sus referencias eliminadas correctamente"}

    except Exception as e:
        if conexion:
            conexion.rollback()
        return {"success": False, "message": f"Error al eliminar el contacto: {str(e)}"}
    finally:
        if cursor:
            cursor.close()
        if conexion:
            conexion.close()
