import logging
from django.conf import settings

from apps.appointments.services.notification_context import AppointmentNotificationContext
from apps.appointments.templates.notification_templates import (
    in_app_message_template,
    sms_template,
    booking_email_context
)
from apps.calls.repositories import MessageRepository
from apps.calls.serializers import MessageCreateSerializer
from apps.calls.services.twilio_sms_service import SmsService
from apps.calls.services.notification_service import NotificationService
from apps.calls.services.email_service import EmailService
from apps.userprofile.services import ProfileServices


logger = logging.getLogger(__name__)


class AppointmentNotificationService:
    """
    Orchestrates all communications triggered by appointment creation.
    - In-app message
    - Notification
    - SMS (async)
    - Email (async)
    """

    @classmethod
    def process(cls, appointment):
        if not appointment:
            logger.error("AppointmentNotificationService.process called with None")
            return None

        ctx = AppointmentNotificationContext.build(appointment)
        recipient = cls._get_recipient(appointment)

        if not recipient:
            emails = settings.EMPTY_RECIPIENT_NOTIFY_EMAILS
            full_name = "No Default Transfer Staff"
            subject = f"No Default Transfer Staff for {ctx['company']}"
            cls._send_email(ctx, list(emails), full_name, subject)
            return None

        message = cls._create_message(recipient, appointment.company, ctx)

        cls._send_in_app_notification(recipient, appointment.company, message)
        cls._send_sms(ctx)

        full_name = ProfileServices.resolve_display_name(user=recipient)
        subject = 'New Appointment Booking'

        emails = settings.EMPTY_RECIPIENT_NOTIFY_EMAILS

        if recipient and recipient.email:
            emails.append(recipient.email)

        cls._send_email(ctx, list(emails), full_name, subject,)

        logger.info(
            "Appointment notifications processed for appointment %s",
            appointment.id,
        )

        return message

    @staticmethod
    def _get_recipient(appointment):
        recipient = appointment.company.default_transfer_staff
        if not recipient:
            logger.warning(
                f"No default_transfer_staff for company {appointment.company_id}"
            )
            return None
        return recipient

    @staticmethod
    def _create_message(recipient, company, ctx):
        body = in_app_message_template(ctx)

        payload = {
            "recipient": recipient.id,
            "customer_name": ctx["customer_name"],
            "customer_number": ctx["customer_number"],
            "subject": "Appointment Message",
            "body": body,
        }

        serializer = MessageCreateSerializer(data=payload)
        serializer.is_valid(raise_exception=True)

        message = MessageRepository.create_message(
            company=company,
            **serializer.validated_data
        )

        logger.info(
            "Message created (id=%s)",
            message.id,
        )

        return message

    @staticmethod
    def _send_in_app_notification(recipient, company, message):
        NotificationService.send_message_notification(
            user=recipient,
            company=company,
            title=message.subject,
            message=message.body,
        )

    @staticmethod
    def _send_sms(ctx):
        sms_text = sms_template(ctx)

        SmsService.send_sms(
            to_number=ctx['bdc_number'],
            message=sms_text,
        )

    @staticmethod
    def _send_email(ctx, emails, full_name, subject):
        if not emails:
            return

        EmailService.send_email(
            subject=subject,
            html_content="appointment/appointment_booking.html",
            recipient_list=emails,
            key=booking_email_context(ctx, full_name),
        )
