"""Chat models — tenant-scoped direct messaging."""

from __future__ import annotations

from typing import ClassVar

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TimeStampedModel


class DirectConversation(TimeStampedModel):
    """A DM thread between exactly two users within one tenant.

    Canonical ordering: ``user1.pk < user2.pk`` is enforced by
    ``get_or_create_between`` so there is only ever one row per pair.
    """

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="chat_conversations",
    )
    user1 = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="chat_conversations_as_user1",
    )
    user2 = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="chat_conversations_as_user2",
    )
    last_message_at = models.DateTimeField(null=True, blank=True, db_index=True)

    class Meta:
        verbose_name = _("direct conversation")
        verbose_name_plural = _("direct conversations")
        constraints: ClassVar = [
            models.UniqueConstraint(
                fields=("tenant", "user1", "user2"),
                name="chat_conversation_unique_pair",
            )
        ]

    @classmethod
    def get_or_create_between(
        cls, tenant_id: int, a_id: int, b_id: int
    ) -> tuple[DirectConversation, bool]:
        """Return (conversation, created) with user1.pk always < user2.pk."""
        lo, hi = (a_id, b_id) if a_id < b_id else (b_id, a_id)
        return cls.objects.get_or_create(
            tenant_id=tenant_id,
            user1_id=lo,
            user2_id=hi,
        )

    def other_user(self, me_id: int) -> int:
        return self.user2_id if self.user1_id == me_id else self.user1_id


class DirectMessage(TimeStampedModel):
    """A single message in a DirectConversation."""

    conversation = models.ForeignKey(
        DirectConversation,
        on_delete=models.CASCADE,
        related_name="messages",
    )
    sender = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="sent_chat_messages",
    )
    body = models.TextField(_("body"), blank=True, default="")
    attachment = models.ForeignKey(
        "storage.FileMetadata",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="chat_messages",
    )
    reply_to = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="replies",
        verbose_name=_("reply to"),
    )
    forwarded_from = models.JSONField(
        _("forwarded from"),
        null=True,
        blank=True,
        help_text="Snapshot of the original message metadata when forwarding.",
    )
    is_read = models.BooleanField(_("is read"), default=False, db_index=True)
    edited_at = models.DateTimeField(_("edited at"), null=True, blank=True)
    is_deleted = models.BooleanField(_("is deleted"), default=False, db_index=True)

    class Meta:
        verbose_name = _("direct message")
        verbose_name_plural = _("direct messages")
        ordering = ("created_at",)


# ---------------------------------------------------------------------------
# Groups & Channels
# ---------------------------------------------------------------------------


class GroupKind(models.TextChoices):
    GROUP = "group", _("Group")
    CHANNEL = "channel", _("Channel")


class GroupMemberRole(models.TextChoices):
    ADMIN = "admin", _("Admin")
    MEMBER = "member", _("Member")


class GroupConversation(TimeStampedModel):
    """A multi-user group chat or broadcast channel within a tenant."""

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="chat_groups",
    )
    name = models.CharField(_("name"), max_length=150)
    description = models.TextField(_("description"), blank=True, default="")
    kind = models.CharField(
        _("kind"),
        max_length=16,
        choices=GroupKind.choices,
        default=GroupKind.GROUP,
        db_index=True,
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="created_chat_groups",
    )
    last_message_at = models.DateTimeField(null=True, blank=True, db_index=True)

    class Meta:
        verbose_name = _("group conversation")
        verbose_name_plural = _("group conversations")

    def __str__(self) -> str:
        return f"{self.get_kind_display()}: {self.name}"


class GroupMember(TimeStampedModel):
    """Membership of a user in a GroupConversation."""

    group = models.ForeignKey(
        GroupConversation,
        on_delete=models.CASCADE,
        related_name="members",
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="chat_group_memberships",
    )
    role = models.CharField(
        _("role"),
        max_length=16,
        choices=GroupMemberRole.choices,
        default=GroupMemberRole.MEMBER,
    )
    last_read_at = models.DateTimeField(_("last read at"), null=True, blank=True)

    class Meta:
        verbose_name = _("group member")
        verbose_name_plural = _("group members")
        constraints: ClassVar = [
            models.UniqueConstraint(
                fields=("group", "user"),
                name="chat_group_member_unique",
            )
        ]


class GroupMessage(TimeStampedModel):
    """A message posted in a GroupConversation."""

    group = models.ForeignKey(
        GroupConversation,
        on_delete=models.CASCADE,
        related_name="messages",
    )
    sender = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="sent_group_messages",
    )
    body = models.TextField(_("body"), blank=True, default="")
    attachment = models.ForeignKey(
        "storage.FileMetadata",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="group_chat_messages",
    )
    reply_to = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="group_replies",
        verbose_name=_("reply to"),
    )
    forwarded_from = models.JSONField(
        _("forwarded from"),
        null=True,
        blank=True,
        help_text="Snapshot of the original message metadata when forwarding.",
    )
    edited_at = models.DateTimeField(_("edited at"), null=True, blank=True)
    is_deleted = models.BooleanField(_("is deleted"), default=False, db_index=True)

    class Meta:
        verbose_name = _("group message")
        verbose_name_plural = _("group messages")
        ordering = ("created_at",)
