from flask import request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime, timedelta
from firebase_admin import credentials, messaging
import pytz
from pymongo import DESCENDING
from bson import ObjectId

#Importaciones propias
from . import notifications_bp
from shared_db_utils import get_db, SERVICES_DB_MAP, USER_DATABASE_NAME, insert_log_in_user_history

# IMPORTACIÓN DEL SERVICIO PUSH
from .push_service import subscribe_token_to_topic, send_topic_notification
from .whatsapp_service import enviar_alerta_whatsapp, enviar_mensaje_prueba_wa

#PARA PRUEBA API WHATSAPP
PHONE_TO_SEND = ["56976494291","56935741906"]
ITG_CHILE_WHATSAPP_SECURE = "ITG_CHILE_WHATSAPP_SECURE"
PLANTILLA_NANOOX = "evento_centro"

@notifications_bp.route('/<SERVICE>/ingest_notifications/<REGION>/<AREA>/<CENTRO>', methods=['POST'], strict_slashes=False)
def ingest_notifications(SERVICE, REGION, AREA, CENTRO):
    service_key = SERVICE.lower()
    target_db_name = SERVICES_DB_MAP.get(service_key)
    
    if not target_db_name:
        return jsonify({"mensaje": f"Servicio '{SERVICE}' no soportado."}), 404

    try:
        # --- OPTIMIZACIÓN: ID ÚNICO Y DEFINITIVO ---
        # 1. Limpiamos las variables originales (sin espacios, sin guiones, capitalizadas)
        r_norm = REGION.replace(' ', '').replace('-', '').capitalize()
        a_norm = AREA.replace(' ', '').replace('-', '').capitalize()
        c_norm = CENTRO.replace(' ', '').replace('-', '').capitalize()
        
        # 2. Creamos la ÚNICA variable de referencia para todo el sistema
        centro_id_unificado = f"{r_norm}-{a_norm}-{c_norm}"
        # ------------------------------------------
        
        received_data = request.json
        if not received_data: return jsonify({"mensaje": "Sin datos"}), 400

        if isinstance(received_data, dict):
            received_data = list(received_data.values())

        if not isinstance(received_data, list):
            return jsonify({"msg": "Se espera lista o dict"}), 400

        client = get_db()
        db = client[target_db_name]
        docs_to_insert = []

        for item in received_data:
            doc = {
                "centro_id": centro_id_unificado, # <--- USAMOS EL ID AQUÍ
                "server_timestamp": datetime.now(),
                "title": f"Alerta {service_key.upper()}",
                "message": item.get("data", "Alerta sin descripción"),
                "severity": "critical",
                "raw_data": {
                    "local_id": item.get("id", "unknown_id"),
                    "local_time": item.get("time", ""),
                    # "original_payload": item
                }
            }
            docs_to_insert.append(doc)

        if not docs_to_insert:
            return jsonify({"msg": "No hay alertas"}), 200

        result = db.notificaciones.insert_many(docs_to_insert)
        inserted_ids = [str(oid) for oid in result.inserted_ids]

        ultimo_mensaje = docs_to_insert[-1]["message"]
        id_jaula= docs_to_insert[-1]["raw_data"]["local_id"]
        event_time= docs_to_insert[-1]["raw_data"]["local_time"]

        # --- REUTILIZACIÓN PARA PUSH ---
        # El Frontend se suscribe directo a "Loslagos-Puertomontt-Itg"
        # 1. Definir Emojis según severidad (puedes sacarlo del payload si viene)
        emoji_status = "⚠️" # Default
        color_hex = "#FFA500" # Naranja default
        
        # Lógica simple de ejemplo (puedes mejorarla según tus datos)
        msg_lower = ultimo_mensaje.lower()
        if "fallo" in msg_lower or "error" in msg_lower or "crítico" in msg_lower or "pérdida" in msg_lower:
            emoji_status = "🚨"
            color_hex = "#FF0000" # Rojo
        elif "ok" in msg_lower or "restablecido" in msg_lower:
            emoji_status = "✅"
            color_hex = "#00FF00" # Verde

        # 2. Construcción de Textos
        # Título: [Emoji] [Centro] - [Servicio]
        titulo_elegante = f"{emoji_status} {c_norm} - {service_key.capitalize()}"
        
        # Cuerpo: El mensaje técnico limpio
        cuerpo_elegante = f"{id_jaula} - {ultimo_mensaje} registrado a las {event_time} de hoy"

        # ---------------------------------------------------------
        # ENVÍO PUSH CON NUEVOS PARÁMETROS
        # ---------------------------------------------------------
        push_status = send_topic_notification(
            centro_id=centro_id_unificado, 
            title=titulo_elegante,
            body=cuerpo_elegante,
            data_payload={
                "service": service_key,
                "notification_id": inserted_ids[-1],
                "centro_id": centro_id_unificado,
                "click_action": "FCM_PLUGIN_ACTIVITY" # Truco para Android
            },
            # Agregamos parámetros visuales para Android
            extra_kwargs={
                "color": color_hex,
                "android_channel_id": "alerts_channel" # Canal de alta prioridad (ver nota abajo)
            }
        )

        # ---------------------------------------------------------------------
        # WHATSAPP EN PRODUCCIÓN: OBTENCIÓN GRANULAR (Permiso + Teléfono)
        # ---------------------------------------------------------------------
        db_users = client[USER_DATABASE_NAME]
        col_users = db_users['users']
        
        # OJO: Para el JSON de permisos, usas el formato "itg-puertomontt-loslagos" (desunificado/minúsculas)
        # Reutilizamos las variables originales normalizadas a minúsculas para el JSON key
        r_key = REGION.lower()
        a_key = AREA.lower()
        
        # Aquí reconstruimos la llave del centro tal como viene en tu JSON de permisos: "itg-puertomontt-loslagos"
        # NOTA: Asegúrate de que esta construcción coincida exactamente con tus llaves en MongoDB.
        # Si en Mongo la llave es "itg-puertomontt-loslagos", usalo así.
        c_key = f"{CENTRO.lower()}-{AREA.lower()}-{REGION.lower()}" 
        s_key = service_key  # Ej: nanoox
        
        # Construimos la ruta DOT NOTATION para buscar en MongoDB
        # Buscamos: permisos -> region -> area -> centro -> servicio
        path_to_service = f"permisos.{r_key}.{a_key}.{c_key}.{s_key}"
        path_status = f"{path_to_service}.status"
        path_phone  = f"{path_to_service}.phone"
        
        # Query Optimizada:
        # Traemos usuarios que:
        # 1. Tengan el status en TRUE para ESTE servicio en ESTE centro.
        # 2. Tengan el campo 'phone' definido en ESTE servicio (existe y no es nulo).
        usuarios_destinatarios = col_users.find({
            path_status: True,
            path_phone: {"$exists": True, "$ne": None}
        })
        
        lista_numeros = []
        
        for usuario in usuarios_destinatarios:
            try:
                # Navegamos manualmente el diccionario para extraer el teléfono
                # (MongoDB ya filtró, pero Python necesita acceder al valor)
                permisos = usuario.get("permisos", {})
                region_data = permisos.get(r_key, {})
                area_data = region_data.get(a_key, {})
                centro_data = area_data.get(c_key, {})
                servicio_data = centro_data.get(s_key, {})
                
                telefono = servicio_data.get("phone")
                
                if telefono:
                    # Limpieza de formato (quitar +, espacios)
                    telefono_limpio = str(telefono).replace("+", "").replace(" ", "").strip()
                    
                    # Validación extra: Que tenga largo de celular válido (ej: 569...)
                    if len(telefono_limpio) >= 8 and telefono_limpio not in lista_numeros:
                        lista_numeros.append(telefono_limpio)
            
            except Exception as e:
                print(f" Error extrayendo teléfono de usuario {usuario.get('username')}: {e}")
                continue
        
        if not lista_numeros:
            print(f" Info: Nadie tiene configurado recibir WhatsApp para {s_key} en {c_key}")
        
        # --- ENVÍO DE WHATSAPP DINÁMICO ---
        whatsapp_results = [] # Aquí guardaremos los datos para la respuesta HTTP
        whatsapp_log_db = []  # Aquí guardaremos los datos para la BASE DE DATOS
        
        # body_dinamico = {"centro": centro_id_unificado} 

        if lista_numeros:
            for numero in lista_numeros:

                # 1. Enviamos el mensaje
                status = enviar_alerta_whatsapp(
                    numero_destino=numero, 
                    nombre_plantilla= PLANTILLA_NANOOX, #"hello_world", # O evento_centro cuando apruebe
                    header_vars={"centro": centro_id_unificado},
                    body_vars=None
                )
                
                # 2. Extraemos el WAMID (El ID sagrado de WhatsApp)
                # La respuesta de Meta suele ser: {'messages': [{'id': 'wamid.HBg...'}]}
                wamid = None
                if status.get("status") == "success":
                    data_resp = status.get("data", {})
                    if "messages" in data_resp and len(data_resp["messages"]) > 0:
                        wamid = data_resp["messages"][0]["id"]

                # 3. Preparamos el objeto para guardar en DB
                log_entry = {
                    "phone": numero,
                    "wamid": wamid,          # <--- ESTO ES LO QUE FALTABA
                    "status": "sent",        # Estado inicial
                    "timestamp": datetime.now()
                }
                
                whatsapp_log_db.append(log_entry)
                
                # Guardamos resultado para el return del API (Node-RED)
                whatsapp_results.append({
                    "numero": numero,
                    "status": status.get("status"),
                    "wamid": wamid,
                    "data": status.get("data")
                })

        # ---------------------------------------------------------
        # 6. CRÍTICO: ACTUALIZAR EL DOCUMENTO EN MONGODB
        # ---------------------------------------------------------
        # Ahora que tenemos los IDs (wamids), debemos guardarlos en la alerta 
        # para que el Webhook pueda encontrarlos cuando lleguen los "Vistos".
        
        if whatsapp_log_db and inserted_ids:
            # Actualizamos la ÚLTIMA alerta insertada (que es la que generó el aviso)
            last_alert_id = result.inserted_ids[-1] # El ObjectId de la última alerta
            
            db.notificaciones.update_one(
                {"_id": last_alert_id},
                {
                    "$set": {
                        "whatsapp_log": whatsapp_log_db, # Guardamos el array completo
                        "delivery_status": "sent"        # Estado global
                    }
                }
            )

        return jsonify({
            "msg": "Notificaciones procesadas",
            "inserted_ids": inserted_ids,
            "push_status": push_status,
            "whatsapp_status": whatsapp_results
        }), 200

    except Exception as e:
        print(f"Error: {e}")
        return jsonify({"mensaje": "Error interno"}), 500
    
@notifications_bp.route('/api/notifications', methods=['GET'])
@jwt_required()
def get_notifications():
    try:
        # 1. Identidad
        current_username = get_jwt_identity() # Asegúrate que esto devuelve el username (ej: "itg7")
        
        # 2. SEGURIDAD: Obtener permisos REALES de la DB
        # Esto devuelve ej: ["Loslagos-Puertomontt-Itg"]
        allowed_centers = obtener_centros_permitidos_usuario(current_username)
        
        if not allowed_centers:
            # Si no tiene permisos, devolvemos vacío inmediatamente
            return jsonify({"data": [], "query_info": {"count": 0}}), 200

        # Parámetros del request
        req_centro_id = request.args.get('centro_id')
        service_req = request.args.get('service')
        limit = int(request.args.get('limit', 50))
        hours_lookback = int(request.args.get('hours', 2))
        
        utc_now = datetime.now()
        cutoff_time = utc_now - timedelta(hours=hours_lookback)

        # 3. Construcción de la Query Segura
        # Base: Tiempo + Centros Permitidos (Security Filter)
        query = {
            "server_timestamp": {"$gte": cutoff_time},
            "centro_id": {"$in": allowed_centers} # <--- EL FILTRO DE SEGURIDAD CLAVE
        }

        # Si el frontend pide un centro específico, validamos que esté en su lista permitida
        if req_centro_id:
            if req_centro_id in allowed_centers:
                query['centro_id'] = req_centro_id
            else:
                # Si pide un centro que no tiene permitido, no devolvemos nada (o error 403)
                return jsonify({"data": [], "msg": "Acceso denegado al centro solicitado"}), 403

        client = get_db()
        raw_results = []

        # Selección de DBs (igual que antes)
        if service_req:
            target_db = SERVICES_DB_MAP.get(service_req.lower())
            dbs_to_search = [target_db] if target_db else []
        else:
            dbs_to_search = list(SERVICES_DB_MAP.values())

        for db_name in dbs_to_search:
            try:
                col = client[db_name]['notificaciones']
                # Nota: Traemos todo (sin proyeccion raw_data: 0) para tener local_id
                cursor = col.find(query).sort("server_timestamp", DESCENDING).limit(limit)
                raw_results.extend(list(cursor))
            except Exception: continue

        # Ordenar y cortar
        raw_results.sort(key=lambda x: x.get('server_timestamp', ''), reverse=True)
        final_slice = raw_results[:limit]

        # --- LÓGICA DE LECTURAS (Igual que antes pero ajustada a username) ---
        notif_ids_map = {doc['_id']: doc for doc in final_slice}
        list_of_ids = list(notif_ids_map.keys())
        read_set = set()
        
        # OJO: Si tu colección de lecturas usa email y el token trae username, 
        # asegúrate de usar el dato correcto. Asumiremos username aquí para consistencia.
        for db_name in dbs_to_search:
            try:
                reads_cursor = client[db_name]['notificaciones_lecturas'].find(
                    {
                        "notification_id": {"$in": list_of_ids},
                        "user_email": current_username # o user_email según corresponda
                    },
                    {"notification_id": 1}
                )
                for r in reads_cursor:
                    read_set.add(r['notification_id'])
            except: continue

        # Formateo Final
        response_data = []
        for doc in final_slice:
            doc_oid = doc['_id']
            doc['id'] = str(doc_oid)
            
            # Extraer local_id
            raw_data = doc.get('raw_data', {})
            if isinstance(raw_data, dict):
                doc['local_id'] = raw_data.get('local_id', None)
            else:
                doc['local_id'] = None
                
            del doc['_id']
            doc['read'] = doc_oid in read_set
            response_data.append(doc)

        return jsonify({
            "data": response_data,
            "query_info": {
                "user": current_username,
                "count": len(response_data)
            }
        }), 200
        
    except Exception as e:
        print(f"Error en GET: {e}")
        return jsonify({"error": str(e)}), 500

@notifications_bp.route('/api/notifications/subscribe', methods=['POST'])
@jwt_required()
def subscribe_device():
    """
    Vía Correcta: 
    1. Recibe un token (que asumimos es NUEVO o VÁLIDO para este usuario).
    2. Calcula permisos reales en DB.
    3. Suscribe SOLO a los permisos reales.
    NO intenta desuscribir de lo prohibido, porque confiamos en que el token
    es fresco o exclusivo de este usuario.
    """
    try:
        current_username = get_jwt_identity()
        data = request.get_json()
        fcm_token = data.get('fcm_token')

        if not fcm_token:
            return jsonify({"msg": "Falta token"}), 400

        # 1. Guardar Token (Siempre útil para debug)
        client = get_db()
        client[USER_DATABASE_NAME]['users'].update_one(
            {"username": current_username}, 
            {"$set": {"fcm_token": fcm_token}}
        )

        # 2. Calcular Permisos Reales (Tu lógica de inversión)
        # Reutilizamos tu función auxiliar 'verificar_permiso_inverso' y 'obtener_todos...'
        # O simplemente calculamos los permitidos.
        
        # Opción A (Más simple): Solo suscribir a lo que tiene permiso AHORA.
        # Como el token es "nuevo" (o único para él), no arrastra basura de otros.
        
        # Usamos tu función auxiliar que ya tenías o la lógica de inversión
        topicos_permitidos = []
        set_universo = obtener_todos_los_topicos_del_sistema()
        user_doc = client[USER_DATABASE_NAME]['users'].find_one({"username": current_username})

        for topic in set_universo:
            if verificar_permiso_inverso(user_doc, topic):
                topicos_permitidos.append(topic)

        # 3. Suscribir Masivamente
        suscritos = 0
        if topicos_permitidos:
            try:
                # Suscribimos a todo lo permitido
                # response = messaging.subscribe_to_topic([fcm_token], topicos_permitidos) # Ojo: validar si tu versión de SDK soporta lista en topic, sino iterar.
                # Si tu SDK pide iterar:
                for t in topicos_permitidos:
                    subscribe_token_to_topic([fcm_token], t)
                    # messaging.subscribe_to_topic([fcm_token], t)
                suscritos = len(topicos_permitidos)
            except Exception as e:
                print(f"Error suscribiendo: {e}")

        return jsonify({
            "status": "success", 
            "msg": f"Usuario {current_username} suscrito a {suscritos} centros.",
            "topics": topicos_permitidos
        }), 200

    except Exception as e:
        return jsonify({"error": str(e)}), 500

@notifications_bp.route('/api/logout_push', methods=['POST'])
@jwt_required()
def logout_push_device():
    """
    Ruta de LIMPIEZA: Recibe el token que se va a destruir y
    fuerza la desuscripción de todos los tópicos del sistema.
    """
    try:
        current_username = get_jwt_identity()
        data = request.get_json()
        fcm_token = data.get('fcm_token')
        
        if not fcm_token:
            return jsonify({"msg": "Token requerido"}), 400

        print(f"👋 [LOGOUT] Iniciando limpieza para usuario {current_username}")

        # 1. Obtener TODOS los tópicos que existen en tu sistema
        # (Usamos tu función auxiliar que escanea notificaciones/usuarios)
        todos_los_temas = obtener_todos_los_topicos_del_sistema()
        
        # 2. Desuscripción Masiva en Firebase
        # Esto asegura que si el deleteToken() del frontend falla por red,
        # al menos el backend ya sacó al usuario de los grupos.
        count = 0
        if todos_los_temas:
            # Firebase permite desuscribir hasta 1000 a la vez, pero iteramos para seguridad
            for tema in todos_los_temas:
                try:
                    response = messaging.unsubscribe_from_topic([fcm_token], tema)
                    if response.success_count > 0:
                        count += 1
                except: pass

        # 3. Borrar el token de la DB del usuario
        client = get_db()
        client[USER_DATABASE_NAME]['users'].update_one(
            {"username": current_username},
            {"$unset": {"fcm_token": ""}} # Borramos el campo
        )

        print(f"✅ [LOGOUT] Token limpiado de {count} temas y eliminado de DB.")
        return jsonify({"msg": "Token limpiado"}), 200

    except Exception as e:
        print(f"Error en logout_push: {e}")
        return jsonify({"error": str(e)}), 500

# --- NUEVA RUTA: ACUSE DE RECIBO (ACK) ---
@notifications_bp.route('/ack/<SERVICE>/<NOTIFICATION_ID>', methods=['POST'])
@jwt_required()
def acknowledge_notification(SERVICE, NOTIFICATION_ID):
    """
    Registra la lectura ('firma') de un usuario sobre una notificación.
    Simula el evento "Usuario hizo clic en la alerta".
    """
    try:
        # 1. Validación de Seguridad Básica
        if not ObjectId.is_valid(NOTIFICATION_ID):
            return jsonify({"msg": "ID de notificación inválido"}), 400

        service_key = SERVICE.lower()
        target_db_name = SERVICES_DB_MAP.get(service_key)
        if not target_db_name:
            return jsonify({"msg": "Servicio no válido"}), 404

        # 2. Obtener identidad del usuario
        user_email =get_jwt_identity()
        
        if not user_email:
            return jsonify({"msg": "Falta el parámetro user_email"}), 400

        client = get_db()
        db = client[target_db_name]

        # 3. Integridad Referencial (Opcional pero Recomendado)
        # Verificamos que la notificación original aún exista en el "Tablón".
        # Si ya expiró (TTL), no tiene sentido firmarla.
        notif_exists = db.notificaciones.find_one({"_id": ObjectId(NOTIFICATION_ID)}, {"centro_id": 1, "message": 1})
        
        if not notif_exists:
            return jsonify({"msg": "La notificación ha expirado o no existe"}), 404

        # 4. Operación UPSERT (La Clave de la Idempotencia)
        # Si el usuario hace clic 10 veces (ansiedad), no creamos 10 registros.
        # Solo actualizamos la fecha 'read_at' del registro existente.
        result = db.notificaciones_lecturas.update_one(
            {
                "notification_id": ObjectId(NOTIFICATION_ID), 
                "user_email": user_email
            },
            {
                "$set": {
                    "notification_id": ObjectId(NOTIFICATION_ID),
                    "user_email": user_email,
                    "centro_id": notif_exists.get("centro_id"), # Guardamos contexto
                    "read_at": datetime.now()
                }
            },
            upsert=True # <--- Crea si no existe, actualiza si existe
        )

        # Diagnóstico para ti en consola
        action = "Created" if result.upserted_id else "Updated"
        print(f"[ACK] {user_email} -> Notif {NOTIFICATION_ID} ({action})")

        # 3. Registrar en Historial Global de Usuarios (Auditoría Permanente)
        if result.upserted_id:
            try:
                # Conexión a la DB de Usuarios
                db_users = client[USER_DATABASE_NAME] 
                col_history = db_users['historial_users']

                user_doc = db_users.users.find_one(
                    {"email": user_email}, 
                    {"username": 1} # Proyección: Solo traemos el username
                )
                
                real_username = user_doc['username'] if user_doc and 'username' in user_doc else user_email

                # Preparamos el objeto de datos para tu función
                log_data = {
                    "service": service_key.upper(),
                    "centro": notif_exists.get("centro_id", "Desconocido"),
                    "message": notif_exists.get("message", "Alerta sin texto")
                }
                
                insert_log_in_user_history(
                    col_history, 
                    real_username, 
                    log_data, 
                    'read_notification'
                )
            except Exception as e:
                print(f"Error escribiendo historial usuario: {e}")
                # No retornamos error 500 porque el ACK técnico sí funcionó.

        return jsonify({
            "status": "success", 
            "msg": "Lectura registrada correctamente",
            "action": action
        }), 200

    except Exception as e:
        print(f"Error en ACK: {e}")
        return jsonify({"msg": "Error interno del servidor", "error": str(e)}), 500

@notifications_bp.route('/whatsapp/webhook', methods=['GET', 'POST'])
def whatsapp_webhook():
    # -----------------------------------------------------------
    # 1. VERIFICACIÓN DE META
    # -----------------------------------------------------------
    if request.method == 'GET':
        VERIFY_TOKEN = os.environ.get("ITG_CHILE_WHATSAPP_SECURE", "tu_token_aqui")
        
        mode = request.args.get('hub.mode')
        token = request.args.get('hub.verify_token')
        challenge = request.args.get('hub.challenge')

        if mode == 'subscribe' and token == VERIFY_TOKEN:
            print("[WEBHOOK] Meta ha verificado la URL exitosamente.")
            return challenge, 200
        else:
            print("[WEBHOOK] Intento de verificación fallido.")
            return 'Forbidden', 403

    # -----------------------------------------------------------
    # 2. RECEPCIÓN DE EVENTOS (Lectura)
    # -----------------------------------------------------------
    elif request.method == 'POST':
        data = request.json
        try:
            entry = data.get('entry', [{}])[0]
            changes = entry.get('changes', [{}])[0]
            value = changes.get('value', {})
            
            if 'statuses' in value:
                client = get_db()
                
                for status in value['statuses']:
                    new_status = status['status']   # sent, delivered, read
                    wa_id = status['id']            # WAMID
                    numero_meta = status['recipient_id'] # Teléfono que reporta Meta (ej: 56935741906)
                    timestamp = status.get('timestamp')

                    print(f" [WHATSAPP] {numero_meta} -> Estado: {new_status}")

                    # ==========================================================
                    # A. TRAZABILIDAD (Actualizar Alerta) - Mismo código de antes
                    # ==========================================================
                    target_dbs = list(SERVICES_DB_MAP.values()) 
                    for db_name in target_dbs:
                        db = client[db_name]
                        col_notif = db.notificaciones
                        result = col_notif.update_one(
                            {"whatsapp_log.wamid": wa_id}, 
                            {
                                "$set": {
                                    "whatsapp_log.$.status": new_status,
                                    "whatsapp_log.$.updated_at": datetime.now()
                                }
                            }
                        )
                        if result.modified_count > 0:
                            print(f" [DB UPDATE] Alerta actualizada en {db_name}")
                            break 

                    # ==========================================================
                    # B. HISTORIAL (Búsqueda Recursiva Definitiva)
                    # ==========================================================
                    if new_status == 'read':
                        db_users = client[USER_DATABASE_NAME] 
                        col_users = db_users['users']
                        col_history = db_users['historial_users']
                        
                        # --- HELPER: Función que camina por el JSON buscando "phone" ---
                        def existe_telefono_en_estructura(data, target_phone):
                            target_phone = str(target_phone).strip()
                            
                            if isinstance(data, dict):
                                for k, v in data.items():
                                    # 1. Si encontramos una llave "phone", comparamos el valor
                                    if k == "phone" and v:
                                        # Limpiamos el valor de la DB (quitamos + o espacios)
                                        db_phone = str(v).replace("+", "").replace(" ", "").strip()
                                        if db_phone == target_phone:
                                            return True
                                    
                                    # 2. Si el valor es otro diccionario (ej: region, area...), entramos recursivamente
                                    if isinstance(v, (dict, list)):
                                        if existe_telefono_en_estructura(v, target_phone):
                                            return True
                                            
                            elif isinstance(data, list):
                                for item in data:
                                    if existe_telefono_en_estructura(item, target_phone):
                                        return True
                            
                            return False
                        # -------------------------------------------------------------

                        # 1. Traemos TODOS los usuarios (Es rápido, son metadatos)
                        # Proyección para traer solo lo necesario y no sobrecargar memoria
                        cursor_users = col_users.find({}, {"username": 1, "phone": 1, "permisos": 1})
                        
                        usuario_encontrado = None
                        
                        for u in cursor_users:
                            # Caso B: Tiene el teléfono escondido en permisos (ej: salva)
                            permisos = u.get("permisos")
                            if permisos and existe_telefono_en_estructura(permisos, numero_meta):
                                usuario_encontrado = u
                                break
                        
                        # 2. Si encontramos al dueño, guardamos el log
                        if usuario_encontrado:
                            real_username = usuario_encontrado.get('username', 'Desconocido')
                            
                            log_data = {
                                "service": "WHATSAPP",
                                "centro": "Notificación Externa",
                                "action": "message_read",
                                "message_id": wa_id,
                                "details": f"Usuario {real_username} leyó la alerta."
                            }
                            
                            insert_log_in_user_history(
                                col_history, 
                                real_username, 
                                log_data, 
                                'read_notification'
                            )
                            print(f"[HISTORIAL] ÉXITO: Registrado 'Visto' para {real_username}")
                        else:
                            print(f" [HISTORIAL] Teléfono {numero_meta} reportó lectura pero no se encontró dueño en DB.")

        except Exception as e:
            print(f" [WEBHOOK ERROR] Procesando: {e}")

        return 'EVENT_RECEIVED', 200

@notifications_bp.route('/test-whatsapp/<numero>', methods=['GET'])
def trigger_whatsapp_test(numero):
    """
    Ruta de prueba. Se usa GET para poder ejecutarla fácilmente 
    desde la barra de direcciones del navegador.
    Ejemplo: https://test.itgchile.com/itg_7xR9L2m_secure/test-whatsapp/56912345678
    """
    try:
        resultado = enviar_mensaje_prueba_wa(numero)
        
        if resultado["status"] == "success":
            return jsonify(resultado), 200
        else:
            return jsonify(resultado), 400
            
    except Exception as e:
        print(f"Error en ruta de WhatsApp: {e}")
        return jsonify({"msg": "Error interno"}), 500


def obtener_centros_permitidos_usuario(username):
    """
    Retorna una lista de IDs de centros (formato Topic) permitidos para el usuario.
    Ej: ['Loslagos-Puertomontt-Itg', 'Aysen-Aysen-Puntacola']
    """
    client = get_db()
    users_col = client[USER_DATABASE_NAME].users
    user = users_col.find_one({"username": username})
    
    if not user or 'permisos' not in user:
        return []

    centros_permitidos = []
    permisos = user.get('permisos', {})

    # Recorremos la estructura: Region -> Area -> Centro -> Servicio
    for region, areas in permisos.items():
        for area, centros_dict in areas.items():
            for centro_raw, servicios in centros_dict.items():
                # Verificar si tiene AL MENOS UN servicio activo en este centro
                tiene_acceso = False
                for srv, data in servicios.items():
                    if isinstance(data, dict) and data.get('status') is True:
                        tiene_acceso = True
                        break
                
                if tiene_acceso:
                    # Convertir 'itg-puertomontt-loslagos' -> 'Loslagos-Puertomontt-Itg'
                    try:
                        parts = centro_raw.split('-')
                        if len(parts) >= 3:
                            c_name = parts[0].capitalize()
                            a_name = parts[1].capitalize()
                            r_name = parts[2].capitalize()
                            # Formato Topic/CentroID usado en Notificaciones
                            formatted_id = f"{r_name}-{a_name}-{c_name}"
                            centros_permitidos.append(formatted_id)
                    except: pass
                    
    return centros_permitidos

def obtener_topicos_permitidos(username):
    """
    Consulta la DB y retorna una lista de los tópicos (Centros) 
    a los que el usuario tiene acceso real.
    Retorna ej: ['Loslagos-Puertomontt-Itg', 'Aysen-Aysen-Puntacola']
    """
    try:
        client = get_db()
        # Asegúrate de usar la colección correcta
        users_col = client[USER_DATABASE_NAME]['users']
        user = users_col.find_one({"username": username})
        
        if not user or 'permisos' not in user:
            return []

        topicos_permitidos = []
        permisos = user.get('permisos', {})

        # Recorremos la estructura: Region -> Area -> Centro -> Servicio
        for region, areas in permisos.items():
            for area, centros_dict in areas.items():
                for centro_raw, servicios in centros_dict.items():
                    
                    # Verificamos si tiene AL MENOS UN servicio con status: true
                    tiene_acceso = False
                    for srv, data in servicios.items():
                        if isinstance(data, dict) and data.get('status') is True:
                            tiene_acceso = True
                            break
                    
                    if tiene_acceso:
                        # Convertimos el ID crudo de la DB al formato de Tópico Firebase
                        # Entrada DB: "itg-puertomontt-loslagos"
                        # Salida Tópico: "Loslagos-Puertomontt-Itg"
                        try:
                            parts = centro_raw.split('-')
                            if len(parts) >= 3:
                                c_name = parts[0].capitalize() # Itg
                                a_name = parts[1].capitalize() # Puertomontt
                                r_name = parts[2].capitalize() # Loslagos
                                
                                # Armamos el string final
                                topic_fmt = f"{r_name}-{a_name}-{c_name}"
                                topicos_permitidos.append(topic_fmt)
                        except:
                            continue # Si el nombre está mal formado, lo saltamos
                            
        return topicos_permitidos

    except Exception as e:
        print(f"Error obteniendo permisos para {username}: {e}")
        return []

def obtener_todos_los_topicos_del_sistema():
    """
    Escanea la colección de usuarios para descubrir TODOS los centros (tópicos) que existen.
    Retorna un SET con strings tipo 'Loslagos-Puertomontt-Itg'.
    """
    client = get_db()
    users_col = client[USER_DATABASE_NAME]['users']
    
    todos_los_topicos = set()
    
    # Proyección liviana: solo traemos permisos
    cursor = users_col.find({}, {"permisos": 1})
    
    for user in cursor:
        permisos = user.get('permisos', {})
        for region, areas in permisos.items():
            for area, centros in areas.items():
                for centro_raw, _ in centros.items():
                    # Formateamos a Tópico: itg-puertomontt-loslagos -> Loslagos-Puertomontt-Itg
                    try:
                        parts = centro_raw.split('-')
                        if len(parts) >= 3:
                            c = parts[0].capitalize()
                            a = parts[1].capitalize()
                            r = parts[2].capitalize()
                            todos_los_topicos.add(f"{r}-{a}-{c}")
                    except: pass
    return todos_los_topicos

def verificar_permiso_inverso(user_doc, topic_str):
    """
    Recibe un Tópico: "Loslagos-Puertomontt-Itg"
    Lo transforma a Key DB: "itg-puertomontt-loslagos" (Al revés y minúsculas)
    Y verifica si existe en los permisos del usuario.
    """
    try:
        parts = topic_str.split('-')
        if len(parts) != 3: 
            return False # Formato inválido, no tenemos permiso
        
        # 1. Desarmamos el Tópico (Region, Area, Centro)
        r_topic, a_topic, c_topic = parts
        
        # 2. Transformación para la DB (Minúsculas)
        r_key = r_topic.lower()
        a_key = a_topic.lower()
        c_key = c_topic.lower()
        
        # 3. Reconstrucción de la Llave Invertida (Centro-Area-Region)
        # Esta es la clave exacta que está en tu MongoDB dentro de 'permisos'
        db_centro_key_reversed = f"{c_key}-{a_key}-{r_key}"
        
        # 4. Navegación Segura en el JSON
        permisos = user_doc.get('permisos', {})
        
        # Ruta: permisos -> region -> area -> centro_invertido
        datos_centro = permisos.get(r_key, {}).get(a_key, {}).get(db_centro_key_reversed)
        
        if not datos_centro:
            return False # No existe la entrada en sus permisos
            
        # 5. Verificamos si tiene al menos UN servicio activo (nanoox, enviro, etc)
        for servicio, info in datos_centro.items():
            if isinstance(info, dict) and info.get('status') is True:
                return True # ¡ENCONTRADO! Tiene permiso.
                
        return False # Existe el centro, pero todos sus servicios están en false

    except Exception as e:
        print(f"Error verificando permiso inverso para {topic_str}: {e}")
        return False