# tests/integration/api/v1/admin/test_messages.py
"""
Integration tests for admin messaging endpoints.

Tests the /api/v1/admin/messages/* endpoints.
"""

import pytest

from app.modules.messaging.models import ConversationType, ParticipantType


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesListAPI:
    """Tests for admin message list endpoints."""

    def test_list_conversations_empty(self, client, admin_headers):
        """Test listing conversations when none exist."""
        response = client.get("/api/v1/admin/messages", headers=admin_headers)

        assert response.status_code == 200
        data = response.json()
        assert "conversations" in data
        assert "total" in data
        assert "total_unread" in data
        assert data["conversations"] == []
        assert data["total"] == 0

    def test_list_conversations_requires_auth(self, client):
        """Test that listing requires authentication."""
        response = client.get("/api/v1/admin/messages")
        assert response.status_code == 401

    def test_list_conversations_requires_admin(self, client, auth_headers):
        """Test that listing requires admin role."""
        response = client.get("/api/v1/admin/messages", headers=auth_headers)
        assert response.status_code == 403

    def test_list_conversations_with_data(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test listing conversations with existing data."""
        response = client.get("/api/v1/admin/messages", headers=admin_headers)

        assert response.status_code == 200
        data = response.json()
        assert data["total"] >= 1
        assert len(data["conversations"]) >= 1

        # Check conversation structure
        conv = data["conversations"][0]
        assert "id" in conv
        assert "conversation_type" in conv
        assert "subject" in conv
        assert "is_closed" in conv

    def test_list_conversations_filter_by_type(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test filtering conversations by type."""
        response = client.get(
            "/api/v1/admin/messages",
            params={"conversation_type": "admin_vendor"},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        for conv in data["conversations"]:
            assert conv["conversation_type"] == "admin_vendor"

    def test_list_conversations_filter_closed(
        self, client, admin_headers, closed_conversation
    ):
        """Test filtering closed conversations."""
        response = client.get(
            "/api/v1/admin/messages",
            params={"is_closed": True},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        for conv in data["conversations"]:
            assert conv["is_closed"] is True


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesUnreadCountAPI:
    """Tests for unread count endpoint."""

    def test_get_unread_count(self, client, admin_headers):
        """Test getting unread count."""
        response = client.get("/api/v1/admin/messages/unread-count", headers=admin_headers)

        assert response.status_code == 200
        data = response.json()
        assert "total_unread" in data
        assert isinstance(data["total_unread"], int)

    def test_get_unread_count_with_unread(
        self, client, admin_headers, test_message
    ):
        """Test unread count with unread messages."""
        response = client.get("/api/v1/admin/messages/unread-count", headers=admin_headers)

        assert response.status_code == 200
        data = response.json()
        # The test_message is sent by admin, so no unread count for admin
        assert data["total_unread"] >= 0


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesRecipientsAPI:
    """Tests for recipients endpoint."""

    def test_get_vendor_recipients(
        self, client, admin_headers, test_vendor_with_vendor_user
    ):
        """Test getting vendor recipients."""
        response = client.get(
            "/api/v1/admin/messages/recipients",
            params={"recipient_type": "vendor"},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert "recipients" in data
        assert "total" in data

    def test_get_customer_recipients(self, client, admin_headers, test_customer):
        """Test getting customer recipients."""
        response = client.get(
            "/api/v1/admin/messages/recipients",
            params={"recipient_type": "customer"},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert "recipients" in data
        assert "total" in data

    def test_get_recipients_requires_type(self, client, admin_headers):
        """Test that recipient_type is required."""
        response = client.get("/api/v1/admin/messages/recipients", headers=admin_headers)
        assert response.status_code == 422  # Validation error


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesCreateAPI:
    """Tests for conversation creation."""

    def test_create_conversation_admin_vendor(
        self, client, admin_headers, test_vendor_user, test_vendor_with_vendor_user
    ):
        """Test creating admin-vendor conversation."""
        response = client.post(
            "/api/v1/admin/messages",
            json={
                "conversation_type": "admin_vendor",
                "subject": "Test Conversation",
                "recipient_type": "vendor",
                "recipient_id": test_vendor_user.id,
                "vendor_id": test_vendor_with_vendor_user.id,
                "initial_message": "Hello vendor!",
            },
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["subject"] == "Test Conversation"
        assert data["conversation_type"] == "admin_vendor"
        assert len(data["messages"]) == 1
        assert data["messages"][0]["content"] == "Hello vendor!"

    def test_create_conversation_admin_customer(
        self, client, admin_headers, test_customer, test_vendor
    ):
        """Test creating admin-customer conversation."""
        response = client.post(
            "/api/v1/admin/messages",
            json={
                "conversation_type": "admin_customer",
                "subject": "Customer Support",
                "recipient_type": "customer",
                "recipient_id": test_customer.id,
                "vendor_id": test_vendor.id,
                "initial_message": "How can I help you?",
            },
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["conversation_type"] == "admin_customer"

    def test_create_conversation_wrong_recipient_type(
        self, client, admin_headers, test_vendor_user, test_vendor
    ):
        """Test error when recipient type doesn't match conversation type."""
        response = client.post(
            "/api/v1/admin/messages",
            json={
                "conversation_type": "admin_vendor",
                "subject": "Test",
                "recipient_type": "customer",  # Wrong type
                "recipient_id": 1,
                "vendor_id": test_vendor.id,
            },
            headers=admin_headers,
        )

        assert response.status_code == 400

    def test_create_conversation_invalid_type(
        self, client, admin_headers, test_vendor_user, test_vendor
    ):
        """Test error when admin tries to create vendor_customer conversation."""
        response = client.post(
            "/api/v1/admin/messages",
            json={
                "conversation_type": "vendor_customer",
                "subject": "Test",
                "recipient_type": "customer",
                "recipient_id": 1,
                "vendor_id": test_vendor.id,
            },
            headers=admin_headers,
        )

        assert response.status_code == 400


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesDetailAPI:
    """Tests for conversation detail."""

    def test_get_conversation_detail(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test getting conversation detail."""
        response = client.get(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["id"] == test_conversation_admin_vendor.id
        assert "participants" in data
        assert "messages" in data

    def test_get_conversation_not_found(self, client, admin_headers):
        """Test getting nonexistent conversation."""
        response = client.get("/api/v1/admin/messages/99999", headers=admin_headers)
        assert response.status_code == 404

    def test_get_conversation_marks_read(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test that getting detail marks as read by default."""
        response = client.get(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["unread_count"] == 0


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesSendAPI:
    """Tests for sending messages."""

    def test_send_message(self, client, admin_headers, test_conversation_admin_vendor):
        """Test sending a message."""
        response = client.post(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}/messages",
            data={"content": "Test message content"},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["content"] == "Test message content"
        assert data["sender_type"] == "admin"

    def test_send_message_to_closed(self, client, admin_headers, closed_conversation):
        """Test cannot send to closed conversation."""
        response = client.post(
            f"/api/v1/admin/messages/{closed_conversation.id}/messages",
            data={"content": "Test message"},
            headers=admin_headers,
        )

        assert response.status_code == 400

    def test_send_message_not_found(self, client, admin_headers):
        """Test sending to nonexistent conversation."""
        response = client.post(
            "/api/v1/admin/messages/99999/messages",
            data={"content": "Test message"},
            headers=admin_headers,
        )

        assert response.status_code == 404


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminMessagesActionsAPI:
    """Tests for conversation actions."""

    def test_close_conversation(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test closing a conversation."""
        response = client.post(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}/close",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
        assert "closed" in data["message"].lower()

    def test_close_conversation_not_found(self, client, admin_headers):
        """Test closing nonexistent conversation."""
        response = client.post(
            "/api/v1/admin/messages/99999/close",
            headers=admin_headers,
        )
        assert response.status_code == 404

    def test_reopen_conversation(self, client, admin_headers, closed_conversation):
        """Test reopening a closed conversation."""
        response = client.post(
            f"/api/v1/admin/messages/{closed_conversation.id}/reopen",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
        assert "reopen" in data["message"].lower()

    def test_mark_read(self, client, admin_headers, test_conversation_admin_vendor):
        """Test marking conversation as read."""
        response = client.put(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}/read",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
        assert data["unread_count"] == 0

    def test_update_preferences(
        self, client, admin_headers, test_conversation_admin_vendor
    ):
        """Test updating notification preferences."""
        response = client.put(
            f"/api/v1/admin/messages/{test_conversation_admin_vendor.id}/preferences",
            json={"email_notifications": False, "muted": True},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
