from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django.conf import settings

from .email_service import EmailService
from apps.core.repositories import UserRepository
from apps.core.services import UserService
from apps.calls.repositories import NotificationRepository
from apps.calls.serializers import NotificationSerializer
from apps.calls.constants import NotificationType
import logging


logger = logging.getLogger(__name__)


class NotificationService:

    @staticmethod
    def list_notifications(user, qs = None):
        if qs is None:
            qs = NotificationRepository.base_queryset()

        if user.is_superuser:
            return qs.order_by('-created_at')

        company = getattr(user, "active_company", None)

        return NotificationRepository.list_for_user_by_company(
            user,
            company,
        )

    @staticmethod
    def get_notification(user, notif_id):
        return NotificationRepository.get_by_id(notif_id, user)

    @staticmethod
    def mark_as_read(user, notif_id):
        notif = NotificationService.get_notification(user, notif_id)

        if notif is None:
            return None
        return NotificationRepository.mark_as_read(notif)

    @staticmethod
    def _send_notification_to_managers(
            managers, user, call, display_name,
            customer_phone, title, role_name, company):
        """Helper method to send notifications to managers/admins"""

        recipients = []

        for manager in managers:
            if user and manager.id == user.id:
                continue

            try:
                advisor_name = UserService.get_user_name(user)
                company_name = company.name if company else "Unknown Company"
                message = f"Advisor {advisor_name} from {company_name} missed a call from {display_name}"

                NotificationService.create_and_push_notification(
                    recipient=manager,
                    company=company,
                    notification_type=NotificationType.MISSED_CALL,
                    title=title,
                    message=message,
                    call=call
                )

                recipients.append(manager)

                logger.info(f"Missed call {customer_phone} notification sent to {role_name}: {manager.email}")
            except Exception as e:
                logger.error(f"Error sending notification to {role_name} {manager.email}: {str(e)}")

        return recipients

    @staticmethod
    def send_missed_call_notification(call, user, company, customer_name, customer_phone):
        """
        Send missed call notifications to advisor, all chief admins, and service managers of the company.

        Args:
            call: Call object
            user: User object (the user who missed the call)
            company: Company object
            customer_name: str (customer name or None)
            customer_phone: str (customer phone number)
        """
        try:
            display_name = customer_name if customer_name else "Unknown Customer"
            # company_name = company.name if company else "Unknown Company"

            message = f"Missed call from {display_name}"
            title = "Missed Call"

            all_email_recipients = []

            if user:
                try:
                    NotificationService.create_and_push_notification(
                        recipient=user,
                        company=company,
                        notification_type=NotificationType.MISSED_CALL,
                        title=title,
                        message=message,
                        call=call
                    )

                    logger.info(f"Missed call notification sent to advisor: {user.email}")
                except Exception as e:
                    logger.error(f"Error sending notification to advisor {user.email}: {str(e)}")

                all_email_recipients.append(user)

            chief_admins = UserRepository.get_chief_admins_for_company(company)

            chief_admin_recipients = NotificationService._send_notification_to_managers(
                chief_admins, user, call, display_name,
                customer_phone, title, "chief admin", company
            )

            service_managers = UserRepository.get_service_managers_for_company(company)

            service_manager_recipients = NotificationService._send_notification_to_managers(
                service_managers, user, call, display_name,
                customer_phone, title, "service manager", company
            )

            all_email_recipients.extend(chief_admin_recipients)
            all_email_recipients.extend(service_manager_recipients)

            user_emails = [
                u.email for u in all_email_recipients
                if u and getattr(u, "email", None)
            ]

            static_bcc_emails = settings.EMAIL_BCC if settings.EMAIL_BCC else []

            all_dealership_emails = (
                settings.ALL_DEALERSHIPS_BOOKING_NOTIFY_EMAILS
            ) if settings.ALL_DEALERSHIPS_BOOKING_NOTIFY_EMAILS else []

            unique_emails = list(set(
                user_emails + static_bcc_emails + all_dealership_emails
            ))

            if unique_emails:
                html_content = NotificationService.render_alert_email(
                    title=title,
                    message=message,
                    recipient_name="Team",
                    alert_icon="📞",
                    alert_type="Missed Call",
                    details={
                        "Customer": display_name,
                        "Phone": customer_phone,
                    }
                )

                EmailService.send_email(
                    subject=title,
                    html_content=html_content,
                    recipient_list=[],  # no direct recipient
                    bcc=unique_emails
                )

                logger.info(f"Single BCC email sent to: {unique_emails}")

        except Exception as e:
            logger.error(f"Error in send_missed_call_notification: {str(e)}")

    @staticmethod
    def send_message_notification(user, company, title='', message=''):
        """
        Send message notifications to advisor of company.

        Args:
            user: User object (the user who missed the call)
            title: str (notification title)
            message: str (notification message)
            company: Company object (the company of user)
        """
        if user is None:
            logger.error("Cannot send notification — user is None")
            return

        try:
            NotificationService.create_and_push_notification(
                recipient=user,
                company=company,
                notification_type=NotificationType.MESSAGE,
                title=title,
                message=message,
            )

            logger.info(f"Message notification sent to {user.email}")

        except Exception as e:
            logger.exception(
                "Failed to send message notification to %s: %s",
                user.email, str(e)
            )

    @staticmethod
    def push_realtime_notification(user_id: int, payload: dict):

        channel_layer = get_channel_layer()
        try:
            async_to_sync(channel_layer.group_send)(
                f"user_{user_id}",
                {
                    "type": "send_notification",
                    "data": payload
                }
            )
            logger.info(f"Notification sent to user {user_id}")
        except Exception as e:
            logger.error(f"Failed sending notification to user {user_id}: {str(e)}")

    @staticmethod
    def create_and_push_notification(
            recipient,
            company,
            notification_type,
            title,
            message,
            call=None
    ):
        """Create a new notification and push it in real-time"""
        try:
            notif = NotificationRepository.create_notification(
                recipient=recipient,
                company=company,
                notification_type=notification_type,
                title=title,
                message=message,
                call=call
            )

            payload = NotificationSerializer(notif).data

            NotificationService.push_realtime_notification(
                recipient.id, payload
            )

            return notif
        except Exception as e:
            logger.error(f"Error creating/pushing notification to user {recipient.id}: {str(e)}")
            return None

    @staticmethod
    def render_alert_email(title, message, **kwargs):
        from django.template.loader import render_to_string
        from django.utils import timezone

        context = {
            "alert_title": title,
            "alert_message": message,
            "current_year": timezone.now().year,
            **kwargs
        }

        return render_to_string("alerts/general_alert.html", context)
