"""Chat serializers."""

from __future__ import annotations

from django.contrib.auth import get_user_model
from rest_framework import serializers

from .models import DirectConversation, DirectMessage, GroupConversation, GroupMember, GroupMessage

User = get_user_model()


class ChatUserSerializer(serializers.ModelSerializer):
    full_name = serializers.SerializerMethodField()
    username = serializers.CharField(read_only=True)

    class Meta:
        model = User
        fields = ("id", "email", "username", "full_name")

    def get_full_name(self, obj: object) -> str:
        name = f"{obj.first_name} {obj.last_name}".strip()
        return name or obj.email or obj.username or ""


class AttachmentSerializer(serializers.Serializer):
    id = serializers.UUIDField(read_only=True)
    filename = serializers.CharField(read_only=True)
    content_type = serializers.CharField(read_only=True)
    size_bytes = serializers.IntegerField(read_only=True)
    url = serializers.SerializerMethodField()

    def get_url(self, obj) -> str:
        request = self.context.get("request")
        from simorgh.apps.storage.providers import get_default_provider
        provider = get_default_provider()
        url = provider.url(obj.path)
        if request and not url.startswith("http"):
            return request.build_absolute_uri(url)
        return url


class ReplyInfoSerializer(serializers.Serializer):
    """Lightweight reference to the message being replied to."""
    id = serializers.IntegerField(read_only=True)
    sender_id = serializers.IntegerField(read_only=True)
    sender_name = serializers.CharField(read_only=True)
    body = serializers.CharField(read_only=True)
    is_deleted = serializers.BooleanField(read_only=True)


class DirectMessageSerializer(serializers.ModelSerializer):
    sender_id = serializers.IntegerField(read_only=True)
    sender_name = serializers.SerializerMethodField()
    attachment = serializers.SerializerMethodField()
    reply_to = serializers.SerializerMethodField()
    forwarded_from = serializers.JSONField(read_only=True)

    class Meta:
        model = DirectMessage
        fields = (
            "id", "sender_id", "sender_name", "body", "attachment",
            "reply_to", "forwarded_from",
            "is_read", "created_at", "edited_at", "is_deleted",
        )

    def get_sender_name(self, obj: DirectMessage) -> str:
        name = f"{obj.sender.first_name} {obj.sender.last_name}".strip()
        return name or obj.sender.email

    def get_attachment(self, obj: DirectMessage) -> dict | None:
        if obj.attachment_id is None:
            return None
        return AttachmentSerializer(obj.attachment, context=self.context).data

    def get_reply_to(self, obj: DirectMessage) -> dict | None:
        if obj.reply_to_id is None:
            return None
        reply_msg = obj.reply_to
        sender_name = (
            f"{reply_msg.sender.first_name} {reply_msg.sender.last_name}".strip()
            or reply_msg.sender.email
        )
        return {
            "id": reply_msg.id,
            "sender_id": reply_msg.sender_id,
            "sender_name": sender_name,
            "body": reply_msg.body,
            "is_deleted": reply_msg.is_deleted,
        }


class ConversationSerializer(serializers.ModelSerializer):
    other_user = serializers.SerializerMethodField()
    last_message = serializers.SerializerMethodField()
    unread_count = serializers.SerializerMethodField()

    class Meta:
        model = DirectConversation
        fields = ("id", "other_user", "last_message", "unread_count", "last_message_at")

    def get_other_user(self, obj: DirectConversation) -> dict:
        me_id = self.context["request"].user.pk
        other_id = obj.other_user(me_id)
        try:
            u = User.objects.get(pk=other_id)
            name = f"{u.first_name} {u.last_name}".strip() or u.email
            return {"id": u.pk, "email": u.email, "full_name": name}
        except User.DoesNotExist:
            return {"id": other_id, "email": "", "full_name": "Unknown"}

    def get_last_message(self, obj: DirectConversation) -> dict | None:
        msg = obj.messages.order_by("-created_at").first()
        if msg is None:
            return None
        return {"body": msg.body, "created_at": msg.created_at}

    def get_unread_count(self, obj: DirectConversation) -> int:
        me_id = self.context["request"].user.pk
        return obj.messages.filter(is_read=False).exclude(sender_id=me_id).count()


# ---------------------------------------------------------------------------
# Groups & Channels
# ---------------------------------------------------------------------------


class GroupConversationSerializer(serializers.ModelSerializer):
    member_count = serializers.SerializerMethodField()
    unread_count = serializers.SerializerMethodField()
    last_message = serializers.SerializerMethodField()
    my_role = serializers.SerializerMethodField()

    class Meta:
        model = GroupConversation
        fields = (
            "id", "name", "description", "kind",
            "member_count", "unread_count", "last_message",
            "last_message_at", "my_role",
        )

    def get_member_count(self, obj: GroupConversation) -> int:
        return obj.members.count()

    def get_unread_count(self, obj: GroupConversation) -> int:
        me_id = self.context["request"].user.pk
        member = obj.members.filter(user_id=me_id).first()
        if member is None:
            return 0
        if member.last_read_at is None:
            return obj.messages.count()
        return obj.messages.filter(created_at__gt=member.last_read_at).count()

    def get_last_message(self, obj: GroupConversation) -> dict | None:
        msg = obj.messages.order_by("-created_at").first()
        if msg is None:
            return None
        return {"body": msg.body, "created_at": str(msg.created_at)}

    def get_my_role(self, obj: GroupConversation) -> str | None:
        me_id = self.context["request"].user.pk
        member = obj.members.filter(user_id=me_id).first()
        return member.role if member else None


class GroupMemberSerializer(serializers.ModelSerializer):
    user = ChatUserSerializer(read_only=True)

    class Meta:
        model = GroupMember
        fields = ("id", "user", "role", "last_read_at", "created_at")


class GroupMessageSerializer(serializers.ModelSerializer):
    sender_id = serializers.IntegerField(read_only=True)
    sender_name = serializers.SerializerMethodField()
    attachment = serializers.SerializerMethodField()
    reply_to = serializers.SerializerMethodField()
    forwarded_from = serializers.JSONField(read_only=True)

    class Meta:
        model = GroupMessage
        fields = (
            "id", "sender_id", "sender_name", "body", "attachment",
            "reply_to", "forwarded_from",
            "created_at", "edited_at", "is_deleted",
        )

    def get_sender_name(self, obj: GroupMessage) -> str:
        u = obj.sender
        return f"{u.first_name} {u.last_name}".strip() or u.email

    def get_attachment(self, obj: GroupMessage) -> dict | None:
        if obj.attachment_id is None:
            return None
        return AttachmentSerializer(obj.attachment, context=self.context).data

    def get_reply_to(self, obj: GroupMessage) -> dict | None:
        if obj.reply_to_id is None:
            return None
        reply_msg = obj.reply_to
        sender_name = (
            f"{reply_msg.sender.first_name} {reply_msg.sender.last_name}".strip()
            or reply_msg.sender.email
        )
        return {
            "id": reply_msg.id,
            "sender_id": reply_msg.sender_id,
            "sender_name": sender_name,
            "body": reply_msg.body,
            "is_deleted": reply_msg.is_deleted,
        }
