"""
Señales — App Notifications
================================
Disparan mensajes WhatsApp automáticos en respuesta a eventos del sistema.
Cada señal encola una tarea Celery (fire-and-forget).
Fallo de WhatsApp NUNCA interrumpe el flujo normal.
"""

import logging

from django.db.models.signals import post_save
from django.dispatch import receiver

from apps.appointments.models import Cita

logger = logging.getLogger("apps.notifications")


def _safe_enqueue(task, *args):
    """
    Encola una tarea Celery sin bloquear si Redis no está disponible.
    Verifica conectividad antes de intentar, para fallar en <100ms.
    """
    import socket

    try:
        # Test rápido de conectividad al broker (Redis)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(0.5)
        result = sock.connect_ex(("localhost", 6379))
        sock.close()
        if result != 0:
            logger.debug("Redis no disponible (port check). Tarea %s no encolada.", task.name)
            return False

        task.apply_async(args=args, ignore_result=True)
        return True
    except Exception:
        logger.warning(
            "No se pudo encolar tarea %s (¿Redis caído?). Ignorando.",
            task.name,
        )
        return False


@receiver(post_save, sender=Cita)
def notificar_cambio_estado_cita(sender, instance, created, **kwargs):
    """
    Cuando una cita cambia a 'confirmada' o 'cancelada',
    encola notificación WhatsApp al paciente.
    """
    if created:
        return  # No notificar al crear, solo al cambiar estado

    try:
        if instance.estado == Cita.Estado.CONFIRMADA:
            from .tasks import notificar_cita_confirmada
            if _safe_enqueue(notificar_cita_confirmada, str(instance.id)):
                logger.info("Señal: cita %s confirmada → WA encolado", instance.id)

        elif instance.estado == Cita.Estado.CANCELADA:
            from .tasks import notificar_cita_cancelada

            # Intentar extraer motivo del último CitaLog
            motivo = ""
            try:
                from apps.appointments.models import CitaLog
                ultimo_log = CitaLog.objects.filter(
                    cita=instance,
                    estado_nuevo=Cita.Estado.CANCELADA,
                ).order_by("-fecha").first()
                if ultimo_log:
                    motivo = ultimo_log.motivo or ""
            except Exception:
                pass

            if _safe_enqueue(notificar_cita_cancelada, str(instance.id), motivo):
                logger.info("Señal: cita %s cancelada → WA encolado", instance.id)

    except Exception:
        logger.exception(
            "Error encolando WA para cita %s (estado=%s)",
            instance.id, instance.estado,
        )


@receiver(post_save, sender="finance.Invoice")
def notificar_nueva_factura(sender, instance, created, **kwargs):
    """
    Cuando se crea una factura nueva, notifica al paciente por WhatsApp.
    """
    if not created:
        return

    try:
        from .tasks import notificar_factura_disponible
        if _safe_enqueue(notificar_factura_disponible, str(instance.id)):
            logger.info("Señal: factura %s creada → WA encolado", instance.numero)
    except Exception:
        logger.exception("Error encolando WA para factura %s", instance.id)
