"""
Notifications models - Multi-channel notification delivery

This module implements the notification system that:
- Sends SMS, WhatsApp, and Email notifications
- Logs all notification attempts
- Tracks delivery status
- Supports retry logic
"""

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models

from apps.core.models import BaseChoices, TimeStampedModel, UUIDModel


class NotificationChannel(BaseChoices):
    """Notification channel choices"""

    SMS = "sms", "SMS"
    WHATSAPP = "whatsapp", "WhatsApp"
    EMAIL = "email", "Email"
    PUSH = "push", "Push Notification"


class NotificationStatus(BaseChoices):
    """Notification delivery status"""

    PENDING = "pending", "Pending"
    SENDING = "sending", "Sending"
    SENT = "sent", "Sent"
    DELIVERED = "delivered", "Delivered"
    FAILED = "failed", "Failed"
    BOUNCED = "bounced", "Bounced"


class NotificationLog(UUIDModel, TimeStampedModel):
    """
    Notification log - tracks all notification attempts.

    Logs every SMS, WhatsApp, and Email sent by the system.
    Used for:
    - Delivery tracking
    - Debugging
    - Compliance
    - Analytics
    """

    # Channel and recipient
    channel = models.CharField(max_length=20, choices=NotificationChannel.choices, db_index=True)
    recipient = models.CharField(max_length=200, help_text="Phone number or email address")

    # Message content
    subject = models.CharField(max_length=500, blank=True)
    message = models.TextField()

    # Related object (generic foreign key)
    content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True, blank=True)
    object_id = models.UUIDField(null=True, blank=True)
    content_object = GenericForeignKey("content_type", "object_id")

    # Delivery status
    status = models.CharField(
        max_length=20, choices=NotificationStatus.choices, default=NotificationStatus.PENDING, db_index=True
    )

    # Timestamps
    sent_at = models.DateTimeField(null=True, blank=True)
    delivered_at = models.DateTimeField(null=True, blank=True)

    # Provider response
    provider = models.CharField(max_length=50, blank=True, help_text="SMS/Email provider used")
    provider_message_id = models.CharField(max_length=200, blank=True, help_text="Message ID from provider")
    provider_response = models.JSONField(default=dict, blank=True, help_text="Full response from provider")

    # Error tracking
    error = models.TextField(blank=True)
    retry_count = models.IntegerField(default=0)

    # Metadata
    metadata = models.JSONField(default=dict, blank=True, help_text="Additional metadata (campaign, template, etc.)")

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["channel", "status", "-created_at"]),
            models.Index(fields=["recipient", "-created_at"]),
            models.Index(fields=["content_type", "object_id"]),
        ]

    def __str__(self):
        return f"{self.channel} to {self.recipient} ({self.status})"

    def mark_sent(self, provider_message_id=None):
        """Mark notification as sent"""
        from django.utils import timezone

        self.status = NotificationStatus.SENT
        self.sent_at = timezone.now()
        if provider_message_id:
            self.provider_message_id = provider_message_id
        self.save(update_fields=["status", "sent_at", "provider_message_id"])

    def mark_delivered(self):
        """Mark notification as delivered"""
        from django.utils import timezone

        self.status = NotificationStatus.DELIVERED
        self.delivered_at = timezone.now()
        self.save(update_fields=["status", "delivered_at"])

    def mark_failed(self, error_message):
        """Mark notification as failed"""
        self.status = NotificationStatus.FAILED
        self.error = error_message
        self.retry_count += 1
        self.save(update_fields=["status", "error", "retry_count"])


class NotificationTemplate(UUIDModel, TimeStampedModel):
    """
    Notification template for consistent messaging.

    Supports:
    - Bilingual templates (AR/EN)
    - Variable substitution
    - Multiple channels
    """

    name = models.CharField(max_length=200, unique=True)
    description = models.TextField(blank=True)

    # Template type
    template_type = models.CharField(
        max_length=50,
        choices=[
            ("survey_invitation", "Survey Invitation"),
            ("survey_reminder", "Survey Reminder"),
            ("complaint_acknowledgment", "Complaint Acknowledgment"),
            ("complaint_update", "Complaint Update"),
            ("action_assignment", "Action Assignment"),
            ("sla_reminder", "SLA Reminder"),
            ("sla_breach", "SLA Breach"),
            ("onboarding_invitation", "Onboarding Invitation"),
            ("onboarding_reminder", "Onboarding Reminder"),
            ("onboarding_completion", "Onboarding Completion"),
        ],
        db_index=True,
    )

    # Channel-specific templates
    sms_template = models.TextField(blank=True, help_text="SMS template with {{variables}}")
    sms_template_ar = models.TextField(blank=True)

    whatsapp_template = models.TextField(blank=True, help_text="WhatsApp template with {{variables}}")
    whatsapp_template_ar = models.TextField(blank=True)

    email_subject = models.CharField(max_length=500, blank=True)
    email_subject_ar = models.CharField(max_length=500, blank=True)
    email_template = models.TextField(blank=True, help_text="Email HTML template with {{variables}}")
    email_template_ar = models.TextField(blank=True)

    # Configuration
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name

    def render(self, channel: str, language: str = "en", context: dict = None) -> str:
        """
        Render template for given channel and language with variable substitution.

        Args:
            channel: 'sms', 'whatsapp', or 'email'
            language: 'en' or 'ar'
            context: Dictionary of variables for substitution

        Returns:
            Rendered template string
        """
        context = context or {}

        # Select template based on channel and language
        if channel == "sms":
            template = self.sms_template_ar if language == "ar" and self.sms_template_ar else self.sms_template
        elif channel == "whatsapp":
            template = (
                self.whatsapp_template_ar if language == "ar" and self.whatsapp_template_ar else self.whatsapp_template
            )
        elif channel == "email":
            if language == "ar" and self.email_template_ar:
                template = self.email_template_ar
            else:
                template = self.email_template
        else:
            template = ""

        # Simple variable substitution
        rendered = template
        for key, value in context.items():
            rendered = rendered.replace(f"{{{{{key}}}}}", str(value))

        return rendered

    @classmethod
    def resolve_template(cls, template_type: str, hospital_id: str = None) -> "NotificationTemplate":
        """
        Auto-resolve template by type with hospital-specific fallback.

        Args:
            template_type: Type of template to resolve
            hospital_id: Optional hospital ID for hospital-specific templates

        Returns:
            NotificationTemplate instance or None
        """
        # Try hospital-specific template first
        if hospital_id:
            template = cls.objects.filter(
                template_type=template_type, is_active=True, name__startswith=f"{hospital_id}_"
            ).first()
            if template:
                return template

        # Fall back to default template
        return cls.objects.filter(template_type=template_type, is_active=True).first()


class UserNotification(UUIDModel, TimeStampedModel):
    """
    In-app notification for users - created for every email sent.
    Auto-deleted after 30 days via management command.
    """

    user = models.ForeignKey("accounts.User", on_delete=models.CASCADE, related_name="notifications")

    # Content (bilingual)
    title = models.CharField(max_length=200)
    title_ar = models.CharField(max_length=200, blank=True)
    message = models.TextField()
    message_ar = models.TextField(blank=True)

    # Type matching email/notification types
    notification_type = models.CharField(max_length=50)

    # Related object (generic foreign key)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
    object_id = models.UUIDField(null=True, blank=True)
    content_object = GenericForeignKey("content_type", "object_id")

    # Navigation
    action_url = models.CharField(max_length=500, blank=True)

    # Status
    is_read = models.BooleanField(default=False)
    read_at = models.DateTimeField(null=True, blank=True)
    is_dismissed = models.BooleanField(default=False)
    dismissed_at = models.DateTimeField(null=True, blank=True)

    # Link to email log
    email_log = models.ForeignKey(
        NotificationLog, on_delete=models.SET_NULL, null=True, blank=True, related_name="user_notification"
    )

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["user", "is_dismissed", "-created_at"]),
            models.Index(fields=["user", "is_read", "-created_at"]),
            models.Index(fields=["created_at"]),
        ]

    def __str__(self):
        return f"{self.notification_type} for {self.user.email}"

    def mark_as_read(self):
        """Mark notification as read"""
        from django.utils import timezone

        self.is_read = True
        self.read_at = timezone.now()
        self.save(update_fields=["is_read", "read_at"])

    def mark_as_dismissed(self):
        """Mark notification as dismissed"""
        from django.utils import timezone

        self.is_dismissed = True
        self.dismissed_at = timezone.now()
        self.save(update_fields=["is_dismissed", "dismissed_at"])

    def get_title(self):
        """Get title based on user language preference"""
        from django.utils.translation import get_language

        if get_language() == "ar" and self.title_ar:
            return self.title_ar
        return self.title

    def get_message(self):
        """Get message based on user language preference"""
        from django.utils.translation import get_language

        if get_language() == "ar" and self.message_ar:
            return self.message_ar
        return self.message

    def get_icon(self):
        """Get icon based on notification type"""
        icons = {
            "complaint_assigned": "user-check",
            "complaint_update": "file-text",
            "sla_reminder": "clock",
            "sla_breach": "alert-triangle",
            "action_required": "alert-circle",
            "mention": "at-sign",
            "survey_invitation": "clipboard",
            "survey_reminder": "bell",
            "onboarding_invitation": "user-plus",
            "system": "bell",
        }
        return icons.get(self.notification_type, "bell")
