import pytest
from django.contrib.auth import get_user_model
from apps.chat.models import Conversation, ConversationParticipant, Message, MessageReaction


@pytest.fixture
def user(db):
    User = get_user_model()
    return User.objects.create_user(email="chat@example.com", password="pass123")


@pytest.fixture
def user2(db):
    User = get_user_model()
    return User.objects.create_user(email="chat2@example.com", password="pass123")


@pytest.fixture
def conversation(db, user, user2):
    conv = Conversation.objects.create(
        created_by=user,
        is_group=False
    )
    ConversationParticipant.objects.create(
        conversation=conv,
        user=user,
        is_admin=True
    )
    ConversationParticipant.objects.create(
        conversation=conv,
        user=user2
    )
    return conv


@pytest.fixture
def message(db, conversation, user):
    return Message.objects.create(
        conversation=conversation,
        sender=user,
        ciphertext="encrypted:Hello, world!"
    )


@pytest.mark.django_db
class TestConversationModel:
    def test_create_conversation(self, user):
        conv = Conversation.objects.create(
            created_by=user,
            is_group=False
        )
        assert conv.is_group is False
        assert conv.created_by == user

    def test_create_group_conversation(self, user):
        conv = Conversation.objects.create(
            name="Team Chat",
            created_by=user,
            is_group=True
        )
        assert conv.is_group is True
        assert conv.name == "Team Chat"

    def test_add_participants(self, user, user2):
        conv = Conversation.objects.create(created_by=user)
        ConversationParticipant.objects.create(conversation=conv, user=user)
        ConversationParticipant.objects.create(conversation=conv, user=user2)
        assert conv.participants.count() == 2

    def test_conversation_str(self, user):
        conv = Conversation.objects.create(created_by=user, name="Test Chat")
        assert str(conv) == "Test Chat"


@pytest.mark.django_db
class TestMessageModel:
    def test_create_message(self, conversation, user):
        msg = Message.objects.create(
            conversation=conversation,
            sender=user,
            ciphertext="encrypted:Test message"
        )
        assert msg.ciphertext == "encrypted:Test message"
        assert msg.sender == user
        assert msg.is_read is False

    def test_message_ordering(self, conversation, user):
        msg1 = Message.objects.create(conversation=conversation, sender=user, ciphertext="First")
        msg2 = Message.objects.create(conversation=conversation, sender=user, ciphertext="Second")
        messages = list(conversation.messages.all())
        assert messages[0] == msg1
        assert messages[1] == msg2

    def test_message_with_attachment(self, conversation, user):
        msg = Message.objects.create(
            conversation=conversation,
            sender=user,
            ciphertext="Image",
            has_attachments=True,
        )
        assert msg.has_attachments is True

    def test_mark_message_read(self, message):
        message.is_read = True
        message.save()
        message.refresh_from_db()
        assert message.is_read is True


@pytest.mark.django_db
class TestMessageReactionModel:
    def test_add_reaction(self, message, user):
        reaction = MessageReaction.objects.create(
            message=message,
            user=user,
            reaction="👍"
        )
        assert reaction.reaction == "👍"
        assert message.reactions.count() == 1

    def test_unique_reaction_per_user(self, message, user):
        MessageReaction.objects.create(message=message, user=user, reaction="👍")
        with pytest.raises(Exception):
            MessageReaction.objects.create(message=message, user=user, reaction="👍")
