"""
Chat Service — API Tests.

تست‌های کامل REST API سرویس چت.
"""
import pytest
from rest_framework import status

from apps.services.chat.models import (
    Channel,
    ChannelMember,
    Message,
    MessageReadReceipt,
    UserPresence,
    ChannelType,
    MemberRole,
    MemberStatus,
    PresenceStatus,
)


# ══════════════════════════════════════════════════════════════
# Channel API
# ══════════════════════════════════════════════════════════════

@pytest.mark.django_db
class TestChannelAPI:
    """Tests for the Channel endpoints."""

    def test_list_channels_unauthenticated(self, api_client):
        """Unauthenticated users get 401."""
        response = api_client.get(
            '/api/v1/chat/channels/', HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_401_UNAUTHORIZED

    def test_list_channels_empty(self, authenticated_client):
        """Authenticated user with no channels gets empty list."""
        response = authenticated_client.get(
            '/api/v1/chat/channels/', HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_list_channels(self, authenticated_client, group_channel):
        """User sees channels they are a member of."""
        response = authenticated_client.get(
            '/api/v1/chat/channels/', HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_create_group_channel(self, authenticated_client, tenant):
        """Create a new group channel."""
        response = authenticated_client.post(
            '/api/v1/chat/channels/',
            data={
                'name': 'کانال تست',
                'channel_type': 'group',
                'description': 'توضیحات تست',
            },
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_201_CREATED
        data = response.data.get('data', response.data)
        assert data['name'] == 'کانال تست'
        assert data['channel_type'] == 'group'

    def test_create_public_channel(self, authenticated_client):
        """Create a public channel."""
        response = authenticated_client.post(
            '/api/v1/chat/channels/',
            data={
                'name': 'اطلاعیه‌های عمومی',
                'channel_type': 'public',
            },
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_201_CREATED
        data = response.data.get('data', response.data)
        assert data['channel_type'] == 'public'

    def test_retrieve_channel(self, authenticated_client, group_channel):
        """Get channel detail."""
        response = authenticated_client.get(
            f'/api/v1/chat/channels/{group_channel.id}/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_update_channel(self, authenticated_client, group_channel):
        """Update channel name via PATCH."""
        response = authenticated_client.patch(
            f'/api/v1/chat/channels/{group_channel.id}/',
            data={'name': 'نام جدید'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert data['name'] == 'نام جدید'

    def test_archive_channel(self, authenticated_client, group_channel):
        """Archive a channel."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/archive/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        group_channel.refresh_from_db()
        assert group_channel.is_archived is True


# ══════════════════════════════════════════════════════════════
# Members API
# ══════════════════════════════════════════════════════════════

@pytest.mark.django_db
class TestMembersAPI:
    """Tests for channel membership endpoints."""

    def test_list_members(self, authenticated_client, group_channel):
        """List channel members."""
        response = authenticated_client.get(
            f'/api/v1/chat/channels/{group_channel.id}/members/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_add_member(self, authenticated_client, group_channel, other_user):
        """Add a member to the channel."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/add-member/',
            data={'user_id': other_user.id},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        assert ChannelMember.objects.filter(
            channel=group_channel,
            user=other_user,
            status=MemberStatus.ACTIVE,
        ).exists()

    def test_remove_member(
        self, authenticated_client, channel_with_other_member, other_user,
    ):
        """Remove a member from the channel."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{channel_with_other_member.id}/remove-member/',
            data={'user_id': other_user.id},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        member = ChannelMember.objects.get(
            channel=channel_with_other_member,
            user=other_user,
        )
        assert member.status == MemberStatus.LEFT


# ══════════════════════════════════════════════════════════════
# Direct Chat API
# ══════════════════════════════════════════════════════════════

@pytest.mark.django_db
class TestDirectChatAPI:
    """Tests for direct chat endpoints."""

    def test_create_direct_chat(self, authenticated_client, other_user, tenant):
        """Create a direct chat with another user."""
        response = authenticated_client.post(
            '/api/v1/chat/direct/',
            data={'user_id': other_user.id},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert data['channel_type'] == 'direct'

    def test_direct_chat_idempotent(
        self, authenticated_client, direct_channel, other_user,
    ):
        """Creating direct chat with same user returns existing channel."""
        response = authenticated_client.post(
            '/api/v1/chat/direct/',
            data={'user_id': other_user.id},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert data['id'] == str(direct_channel.id)


# ══════════════════════════════════════════════════════════════
# Message API
# ══════════════════════════════════════════════════════════════

@pytest.mark.django_db
class TestMessageAPI:
    """Tests for message endpoints."""

    def test_send_message(self, authenticated_client, group_channel):
        """Send a text message."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/send/',
            data={'content': 'سلام دنیا!'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_201_CREATED
        data = response.data.get('data', response.data)
        assert data['content'] == 'سلام دنیا!'

    def test_send_empty_message_allowed(self, authenticated_client, group_channel):
        """Empty content is allowed (for file-only messages)."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/send/',
            data={'content': ''},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_201_CREATED

    def test_list_messages(self, authenticated_client, group_channel, message):
        """List messages in a channel."""
        response = authenticated_client.get(
            f'/api/v1/chat/channels/{group_channel.id}/messages/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert len(data) >= 1

    def test_list_messages_with_limit(
        self, authenticated_client, group_channel, multiple_messages,
    ):
        """Messages support limit parameter."""
        response = authenticated_client.get(
            f'/api/v1/chat/channels/{group_channel.id}/messages/',
            {'limit': 5},
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert len(data) == 5

    def test_edit_message(self, authenticated_client, message):
        """Edit own message via PATCH."""
        response = authenticated_client.patch(
            f'/api/v1/chat/messages/{message.id}/edit/',
            data={'content': 'پیام ویرایش شده'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        message.refresh_from_db()
        assert message.content == 'پیام ویرایش شده'
        assert message.is_edited is True

    def test_edit_other_user_message_forbidden(
        self, other_authenticated_client, message,
    ):
        """Cannot edit another user's message."""
        response = other_authenticated_client.patch(
            f'/api/v1/chat/messages/{message.id}/edit/',
            data={'content': 'هک!'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_403_FORBIDDEN

    def test_soft_delete_message(self, authenticated_client, message):
        """Soft-delete own message via DELETE."""
        response = authenticated_client.delete(
            f'/api/v1/chat/messages/{message.id}/soft-delete/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        message.refresh_from_db()
        assert message.is_deleted is True

    def test_delete_other_user_message_forbidden(
        self, other_authenticated_client, message,
    ):
        """Cannot delete another user's message."""
        response = other_authenticated_client.delete(
            f'/api/v1/chat/messages/{message.id}/soft-delete/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_403_FORBIDDEN

    def test_send_reply(self, authenticated_client, group_channel, message):
        """Send a reply to an existing message."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/send/',
            data={
                'content': 'پاسخ به پیام قبلی',
                'reply_to': str(message.id),
            },
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_201_CREATED

    def test_mark_read(self, authenticated_client, group_channel, message):
        """Mark a message as read via POST."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/mark-read/',
            data={'message_id': str(message.id)},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_search_messages(
        self, authenticated_client, group_channel, message,
    ):
        """Search messages by content via POST."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/search/',
            data={'query': 'تست'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert len(data) >= 1

    def test_search_messages_no_results(
        self, authenticated_client, group_channel, message,
    ):
        """Search with no matches returns empty list."""
        response = authenticated_client.post(
            f'/api/v1/chat/channels/{group_channel.id}/search/',
            data={'query': 'xyz_nonexistent_xyz'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
        data = response.data.get('data', response.data)
        assert len(data) == 0


# ══════════════════════════════════════════════════════════════
# Presence API
# ══════════════════════════════════════════════════════════════

@pytest.mark.django_db
class TestPresenceAPI:
    """Tests for presence endpoints."""

    def test_set_status(self, authenticated_client, user, tenant):
        """Set user's online status."""
        response = authenticated_client.post(
            '/api/v1/chat/presence/set-status/',
            data={'status': 'online', 'custom_status': 'مشغول کار'},
            format='json',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_get_online_users(self, authenticated_client, user, tenant):
        """Get list of online users."""
        UserPresence.objects.update_or_create(
            tenant=tenant,
            user=user,
            defaults={'status': PresenceStatus.ONLINE},
        )
        response = authenticated_client.get(
            '/api/v1/chat/presence/online/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK

    def test_get_my_presence(self, authenticated_client, user, tenant):
        """Get current user's presence."""
        UserPresence.objects.update_or_create(
            tenant=tenant,
            user=user,
            defaults={'status': PresenceStatus.AWAY, 'custom_status': 'دور'},
        )
        response = authenticated_client.get(
            '/api/v1/chat/presence/me/',
            HTTP_HOST='localhost',
        )
        assert response.status_code == status.HTTP_200_OK
