"""
Forma de la respuesta de los envios de mensajeria.

En mensajeria una peticion puede producir varios envios independientes, y
pueden acabar distinto: unos aceptados y otros rechazados por el proveedor.
La respuesta lo refleja en lugar de reducirlo a un booleano.

La version anterior devolvia `{"status": true, "sids": [...]}` y, ante
cualquier fallo, `400 Invalid data` sin decir cuales se habian enviado ya.
"""

from __future__ import annotations

from rest_framework import status
from rest_framework.response import Response

from notifications.models.message import MessageStatus, NotificationMessage

ESTADOS_CORRECTOS = frozenset({MessageStatus.SENT, MessageStatus.DELIVERED})
ESTADOS_PENDIENTES = frozenset({MessageStatus.QUEUED, MessageStatus.SENDING})


def resumen_de_envios(request, mensajes: list[NotificationMessage], channel: str):
    """
    Construye la respuesta a partir del estado real de cada envio.

    * `202` si todos quedaron encolados.
    * `200` si todos salieron.
    * `207` si unos salieron y otros no, con el detalle por destinatario.
    * `502` si ninguno salio.
    """
    for mensaje in mensajes:
        mensaje.refresh_from_db()

    detalle = [
        {
            "message_id": str(m.id),
            "to": (m.to or [""])[0],
            "status": m.status,
            "provider_message_id": m.provider_message_id,
            "error_code": m.error_code or None,
        }
        for m in mensajes
    ]

    encolados = [m for m in mensajes if m.status in ESTADOS_PENDIENTES]
    correctos = [m for m in mensajes if m.status in ESTADOS_CORRECTOS]
    fallidos = [
        m
        for m in mensajes
        if m.status not in ESTADOS_CORRECTOS and m.status not in ESTADOS_PENDIENTES
    ]

    cuerpo = {
        "channel": channel,
        "requested": len(mensajes),
        "queued": len(encolados),
        "sent": len(correctos),
        "failed": len(fallidos),
        "messages": detalle,
        "request_id": getattr(request, "request_id", ""),
    }

    if encolados and not fallidos:
        codigo = status.HTTP_202_ACCEPTED
    elif fallidos and not correctos and not encolados:
        codigo = status.HTTP_502_BAD_GATEWAY
        cuerpo["status"] = "error"
    elif fallidos:
        # Exito parcial: el cliente necesita saber exactamente cuales fallaron
        # para no reenviar los que si salieron.
        codigo = status.HTTP_207_MULTI_STATUS
        cuerpo["status"] = "partial"
    else:
        codigo = status.HTTP_200_OK

    cuerpo.setdefault("status", "ok")
    return Response(cuerpo, status=codigo)
