"""
chat/models.py

Models for the In-App Communication/Chat System.
Supports direct messaging, group chats, file sharing, and emoji reactions.
"""

from django.db import models
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _

from base.models import Company
from employee.models import Employee
from horilla.models import HorillaModel, upload_path


class ChatRoom(HorillaModel):
    """
    Represents a chat room - can be either a direct message (1:1) or group chat.
    """

    ROOM_TYPE_CHOICES = [
        ("direct", _("Direct Message")),
        ("group", _("Group Chat")),
    ]

    name = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_("Room Name"),
        help_text=_("Name of the chat room (required for group chats)"),
    )
    room_type = models.CharField(
        max_length=10,
        choices=ROOM_TYPE_CHOICES,
        default="direct",
        verbose_name=_("Room Type"),
    )
    description = models.TextField(
        null=True,
        blank=True,
        verbose_name=_("Description"),
    )
    room_image = models.ImageField(
        upload_to=upload_path,
        null=True,
        blank=True,
        verbose_name=_("Room Image"),
    )
    company_id = models.ForeignKey(
        Company,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        verbose_name=_("Company"),
        related_name="chat_rooms",
    )

    class Meta:
        verbose_name = _("Chat Room")
        verbose_name_plural = _("Chat Rooms")
        ordering = ["-created_at"]

    def __str__(self):
        if self.room_type == "group":
            return self.name or f"Group #{self.pk}"
        members = self.members.all()[:2]
        if members.count() == 2:
            return f"{members[0].employee_id} & {members[1].employee_id}"
        return f"Chat Room #{self.pk}"

    def get_display_name(self, current_employee=None):
        """
        Get display name for the chat room.
        For direct chats, returns the other participant's name.
        """
        if self.room_type == "group":
            return self.name or f"Group #{self.pk}"
        if current_employee:
            other_member = self.members.exclude(employee_id=current_employee).first()
            if other_member:
                return other_member.employee_id.get_full_name()
        return str(self)

    def get_room_image(self, current_employee=None):
        """
        Get room image URL. For direct chats, returns the other person's avatar.
        """
        if self.room_type == "group" and self.room_image:
            return self.room_image.url
        if current_employee and self.room_type == "direct":
            other_member = self.members.exclude(employee_id=current_employee).first()
            if other_member:
                return other_member.employee_id.get_avatar()
        return None

    def get_last_message(self):
        """Get the most recent message in this chat room."""
        return self.messages.order_by("-created_at").first()

    def get_unread_count(self, employee):
        """Get count of unread messages for a specific employee."""
        member = self.members.filter(employee_id=employee).first()
        if member and member.last_read_at:
            return self.messages.filter(created_at__gt=member.last_read_at).exclude(
                sender=employee
            ).count()
        elif member:
            return self.messages.exclude(sender=employee).count()
        return 0


class ChatRoomMember(HorillaModel):
    """
    Represents membership in a chat room.
    """

    ROLE_CHOICES = [
        ("admin", _("Admin")),
        ("member", _("Member")),
    ]

    chat_room = models.ForeignKey(
        ChatRoom,
        on_delete=models.CASCADE,
        related_name="members",
        verbose_name=_("Chat Room"),
    )
    employee_id = models.ForeignKey(
        Employee,
        on_delete=models.CASCADE,
        related_name="chat_memberships",
        verbose_name=_("Employee"),
    )
    role = models.CharField(
        max_length=10,
        choices=ROLE_CHOICES,
        default="member",
        verbose_name=_("Role"),
    )
    last_read_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_("Last Read At"),
    )
    is_muted = models.BooleanField(
        default=False,
        verbose_name=_("Is Muted"),
    )

    class Meta:
        verbose_name = _("Chat Room Member")
        verbose_name_plural = _("Chat Room Members")
        unique_together = ["chat_room", "employee_id"]

    def __str__(self):
        return f"{self.employee_id} in {self.chat_room}"


class ChatMessage(HorillaModel):
    """
    Represents a message in a chat room.
    """

    MESSAGE_TYPE_CHOICES = [
        ("text", _("Text")),
        ("image", _("Image")),
        ("file", _("File")),
        ("system", _("System")),
    ]

    chat_room = models.ForeignKey(
        ChatRoom,
        on_delete=models.CASCADE,
        related_name="messages",
        verbose_name=_("Chat Room"),
    )
    sender = models.ForeignKey(
        Employee,
        on_delete=models.CASCADE,
        related_name="sent_messages",
        verbose_name=_("Sender"),
    )
    content = models.TextField(
        null=True,
        blank=True,
        verbose_name=_("Content"),
    )
    message_type = models.CharField(
        max_length=10,
        choices=MESSAGE_TYPE_CHOICES,
        default="text",
        verbose_name=_("Message Type"),
    )
    reply_to = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="replies",
        verbose_name=_("Reply To"),
    )
    is_edited = models.BooleanField(
        default=False,
        verbose_name=_("Is Edited"),
    )
    edited_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_("Edited At"),
    )

    class Meta:
        verbose_name = _("Chat Message")
        verbose_name_plural = _("Chat Messages")
        ordering = ["created_at"]

    def __str__(self):
        return f"Message from {self.sender} in {self.chat_room}"

    def get_sender_avatar(self):
        """Get sender's avatar URL."""
        return self.sender.get_avatar()

    def get_sender_name(self):
        """Get sender's full name."""
        return self.sender.get_full_name()


class ChatAttachment(HorillaModel):
    """
    Represents a file or image attachment in a chat message.
    """

    ATTACHMENT_TYPE_CHOICES = [
        ("image", _("Image")),
        ("file", _("File")),
    ]

    message = models.ForeignKey(
        ChatMessage,
        on_delete=models.CASCADE,
        related_name="attachments",
        verbose_name=_("Message"),
    )
    file = models.FileField(
        upload_to=upload_path,
        verbose_name=_("File"),
    )
    file_name = models.CharField(
        max_length=255,
        verbose_name=_("File Name"),
    )
    file_size = models.PositiveIntegerField(
        default=0,
        verbose_name=_("File Size (bytes)"),
    )
    file_type = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        verbose_name=_("File Type"),
    )
    attachment_type = models.CharField(
        max_length=10,
        choices=ATTACHMENT_TYPE_CHOICES,
        default="file",
        verbose_name=_("Attachment Type"),
    )

    class Meta:
        verbose_name = _("Chat Attachment")
        verbose_name_plural = _("Chat Attachments")

    def __str__(self):
        return self.file_name

    def is_image(self):
        """Check if attachment is an image."""
        image_extensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"]
        return any(self.file_name.lower().endswith(ext) for ext in image_extensions)

    def save(self, *args, **kwargs):
        """Set attachment_type based on file extension."""
        if self.is_image():
            self.attachment_type = "image"
        else:
            self.attachment_type = "file"
        super().save(*args, **kwargs)


class MessageReaction(HorillaModel):
    """
    Represents an emoji reaction to a message.
    """

    message = models.ForeignKey(
        ChatMessage,
        on_delete=models.CASCADE,
        related_name="reactions",
        verbose_name=_("Message"),
    )
    employee_id = models.ForeignKey(
        Employee,
        on_delete=models.CASCADE,
        related_name="message_reactions",
        verbose_name=_("Employee"),
    )
    emoji = models.CharField(
        max_length=50,
        verbose_name=_("Emoji"),
    )

    class Meta:
        verbose_name = _("Message Reaction")
        verbose_name_plural = _("Message Reactions")
        unique_together = ["message", "employee_id", "emoji"]

    def __str__(self):
        return f"{self.employee_id} reacted {self.emoji} to message #{self.message.pk}"


# Signal handlers for file cleanup
@receiver(pre_delete, sender=ChatRoom)
def delete_chat_room_image(sender, instance, **kwargs):
    """Delete the room image file when a ChatRoom is deleted."""
    if instance.room_image:
        try:
            instance.room_image.delete(save=False)
        except Exception:
            pass


@receiver(pre_delete, sender='chat.ChatAttachment')
def delete_attachment_file(sender, instance, **kwargs):
    """Delete the attachment file when a ChatAttachment is deleted."""
    if instance.file:
        try:
            instance.file.delete(save=False)
        except Exception:
            pass
