"""
Notificacion de sistema por WhatsApp.

Nota sobre los nombres: este endpoint se llama `/whatsapp/send/template` pero
manda texto libre, y `/whatsapp/send` manda la plantilla. Estan cruzados desde
el principio y se conservan asi para no romper a los clientes.

Se conserva tambien la pregunta periodica de continuidad: cada cierto tiempo
se pregunta al destinatario si quiere seguir recibiendo notificaciones por
este medio. Eso mantiene abierta la ventana de conversacion de WhatsApp, que
es lo que permite mandarle mensajes de texto libre sin plantilla aprobada.
"""

from __future__ import annotations

import logging

from django.conf import settings
from django.utils import timezone
from drf_spectacular.utils import extend_schema
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

from core.authentications.token_auth import TokenAuthentication
from core.permissions import HasScope
from keys.models.api_keys import SCOPE_WHATSAPP_SEND
from notifications.channels.messaging.registry import UnknownProvider, get_provider
from notifications.controllers.v1.mail.conversation import _error
from notifications.models.message import Channel
from notifications.models.numbers import Numbers
from notifications.serializers.whatsapp import WhatsAppTemplateSerializer
from notifications.services.messenger import send_many
from notifications.services.results import resumen_de_envios
from notifications.throttling import SendThrottle

logger = logging.getLogger("notifications.whatsapp")

PREGUNTA_CONTINUIDAD = (
    "¿Quieres seguir recibiendo notificaciones a través de este medio?"
)


def componer_cuerpo(system: str, notification: str) -> str:
    """Arma el texto de la notificacion con el formato de WhatsApp."""
    return (
        "Estimado usuario,\n"
        f"Te informamos que el sistema: *{system}* ha generado la siguiente "
        "notificación:\n"
        f"_{notification}_\n"
        "Por favor, ingresa a la plataforma y continua con el proceso.\n"
        "Gracias,\n"
        "Equipo de Soporte ⚙️"
    )


class Send(APIView):
    """Envia la notificacion de sistema a cada numero."""

    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated, HasScope]
    required_scope = SCOPE_WHATSAPP_SEND
    throttle_classes = [SendThrottle]

    @extend_schema(
        summary="Enviar notificación de sistema por WhatsApp",
        request=WhatsAppTemplateSerializer,
        responses={200: None, 202: None, 207: None, 400: None, 503: None},
    )
    def post(self, request, format=None):
        serializer = WhatsAppTemplateSerializer(
            data=request.data, context={"request": request}
        )
        serializer.is_valid(raise_exception=True)
        datos = serializer.validated_data

        try:
            provider = get_provider()
        except UnknownProvider as exc:
            return _error(
                request,
                "provider_unavailable",
                str(exc),
                status.HTTP_503_SERVICE_UNAVAILABLE,
            )

        cuerpo = componer_cuerpo(datos["system"], datos["notification"])
        send_async = datos.get("send_async", True)

        mensajes = send_many(
            channel=Channel.WHATSAPP,
            numbers=datos["to"],
            body=cuerpo,
            provider_name=provider.name,
            send_async=send_async,
            request=request,
            api_key=getattr(request, "api_key_record", None),
        )

        self._preguntar_continuidad(
            datos["to"], provider.name, send_async, request
        )

        return resumen_de_envios(request, mensajes, Channel.WHATSAPP)

    def _preguntar_continuidad(
        self, numeros: list[str], provider_name: str, send_async: bool, request
    ) -> None:
        """
        Pregunta al destinatario si quiere seguir recibiendo notificaciones.

        Solo si ha pasado el periodo configurado desde la ultima vez. Un fallo
        aqui no debe afectar a la notificacion principal, que ya se envio: se
        registra y se sigue.
        """
        dias = settings.WHATSAPP_REPLY_PROMPT_DAYS
        if dias <= 0:
            return

        ahora = timezone.now()
        limite = ahora - timezone.timedelta(days=dias)

        for numero in numeros:
            try:
                registro, creado = Numbers.objects.get_or_create(
                    number=numero, defaults={"replay_date": ahora}
                )
                if creado or registro.replay_date > limite:
                    continue

                send_many(
                    channel=Channel.WHATSAPP,
                    numbers=[numero],
                    body=PREGUNTA_CONTINUIDAD,
                    provider_name=provider_name,
                    send_async=send_async,
                    request=request,
                    api_key=getattr(request, "api_key_record", None),
                )
                registro.replay_date = ahora
                registro.save(update_fields=["replay_date"])
            except Exception:  # noqa: BLE001 - no debe tumbar el envio principal
                logger.exception(
                    "No se pudo enviar la pregunta de continuidad",
                    extra={"numero": numero},
                )
