"""
Unit tests for notification serializers.
"""
from unittest.mock import Mock, MagicMock
import pytest


class TestNotificationSerializer:
    """Unit tests for the NotificationSerializer."""

    def test_serializer_fields(self):
        """Test that serializer has all required fields."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        serializer = NotificationSerializer()

        expected_fields = [
            'id', 'verb', 'read', 'timestamp', 'data',
            'actor_type', 'actor_display', 'target_type',
            'target_display', 'target_url'
        ]

        assert set(serializer.fields.keys()) == set(expected_fields)

    def test_serializer_read_only_fields(self):
        """Test that appropriate fields are read-only."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Get read-only fields from Meta
        read_only_fields = NotificationSerializer.Meta.read_only_fields

        expected_read_only = [
            'id', 'verb', 'timestamp', 'data',
            'actor_type', 'actor_display', 'target_type',
            'target_display', 'target_url'
        ]

        assert set(read_only_fields) == set(expected_read_only)

    def test_get_actor_type_with_content_type(self):
        """Test get_actor_type returns model name when actor exists."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'user'

        mock_notification = Mock()
        mock_notification.actor_content_type = mock_content_type

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_type(mock_notification)

        # Assert
        assert result == 'user'

    def test_get_actor_type_without_content_type(self):
        """Test get_actor_type returns None when no actor."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_notification = Mock()
        mock_notification.actor_content_type = None

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_type(mock_notification)

        # Assert
        assert result is None

    def test_get_actor_display_with_full_name(self):
        """Test get_actor_display returns full_name when available."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_actor = Mock()
        mock_actor.full_name = "John Doe"
        mock_actor.email = "john@example.com"

        mock_notification = Mock()
        mock_notification.actor = mock_actor

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_display(mock_notification)

        # Assert
        assert result == "John Doe"

    def test_get_actor_display_with_empty_full_name(self):
        """Test get_actor_display returns email when full_name is empty."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_actor = Mock()
        mock_actor.full_name = ""
        mock_actor.email = "john@example.com"

        mock_notification = Mock()
        mock_notification.actor = mock_actor

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_display(mock_notification)

        # Assert
        assert result == "john@example.com"

    def test_get_actor_display_without_full_name_attribute(self):
        """Test get_actor_display uses str() when full_name not available."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_actor = Mock(spec=['__str__'])
        mock_actor.__str__ = Mock(return_value="System Bot")
        del mock_actor.full_name  # Ensure no full_name attribute

        mock_notification = Mock()
        mock_notification.actor = mock_actor

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_display(mock_notification)

        # Assert
        assert result == "System Bot"

    def test_get_actor_display_without_actor(self):
        """Test get_actor_display returns 'System' when no actor."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_notification = Mock()
        mock_notification.actor = None

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_actor_display(mock_notification)

        # Assert
        assert result == 'System'

    def test_get_target_type_with_content_type(self):
        """Test get_target_type returns model name."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'ticket'

        mock_notification = Mock()
        mock_notification.target_content_type = mock_content_type

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_type(mock_notification)

        # Assert
        assert result == 'ticket'

    def test_get_target_type_without_content_type(self):
        """Test get_target_type returns None when no target."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_notification = Mock()
        mock_notification.target_content_type = None

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_type(mock_notification)

        # Assert
        assert result is None

    def test_get_target_display_with_subject(self):
        """Test get_target_display returns subject for tickets."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_target = Mock()
        mock_target.subject = "Urgent: Fix login bug"

        mock_notification = Mock()
        mock_notification.target = mock_target

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_display(mock_notification)

        # Assert
        assert result == "Urgent: Fix login bug"

    def test_get_target_display_with_title(self):
        """Test get_target_display returns title when no subject."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_target = Mock(spec=['title'])
        mock_target.title = "Project Meeting"

        mock_notification = Mock()
        mock_notification.target = mock_target

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_display(mock_notification)

        # Assert
        assert result == "Project Meeting"

    def test_get_target_display_with_name(self):
        """Test get_target_display returns name when no subject/title."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_target = Mock(spec=['name'])
        mock_target.name = "Conference Room A"

        mock_notification = Mock()
        mock_notification.target = mock_target

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_display(mock_notification)

        # Assert
        assert result == "Conference Room A"

    def test_get_target_display_fallback_to_str(self):
        """Test get_target_display uses str() as fallback."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_target = Mock(spec=['__str__'])
        mock_target.__str__ = Mock(return_value="Custom Object")

        mock_notification = Mock()
        mock_notification.target = mock_target

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_display(mock_notification)

        # Assert
        assert result == "Custom Object"

    def test_get_target_display_without_target(self):
        """Test get_target_display returns None when no target."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_notification = Mock()
        mock_notification.target = None

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_display(mock_notification)

        # Assert
        assert result is None

    def test_get_target_url_for_ticket(self):
        """Test get_target_url returns correct URL for ticket."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'ticket'

        mock_notification = Mock()
        mock_notification.target_content_type = mock_content_type
        mock_notification.target_object_id = '42'

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_url(mock_notification)

        # Assert
        assert result == '/tickets?id=42'

    def test_get_target_url_for_event(self):
        """Test get_target_url returns correct URL for event."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'event'

        mock_notification = Mock()
        mock_notification.target_content_type = mock_content_type
        mock_notification.target_object_id = '123'

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_url(mock_notification)

        # Assert
        assert result == '/scheduler?event=123'

    def test_get_target_url_for_appointment(self):
        """Test get_target_url returns correct URL for appointment."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'appointment'

        mock_notification = Mock()
        mock_notification.target_content_type = mock_content_type
        mock_notification.target_object_id = '789'

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_url(mock_notification)

        # Assert
        assert result == '/scheduler?appointment=789'

    def test_get_target_url_for_unmapped_type(self):
        """Test get_target_url returns None for unmapped model types."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_content_type = Mock()
        mock_content_type.model = 'unknown_type'

        mock_notification = Mock()
        mock_notification.target_content_type = mock_content_type
        mock_notification.target_object_id = '999'

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_url(mock_notification)

        # Assert
        assert result is None

    def test_get_target_url_without_content_type(self):
        """Test get_target_url returns None when no content type."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer

        # Arrange
        mock_notification = Mock()
        mock_notification.target_content_type = None

        serializer = NotificationSerializer()

        # Act
        result = serializer.get_target_url(mock_notification)

        # Assert
        assert result is None

    def test_serializer_model_meta(self):
        """Test that serializer Meta.model is correct."""
        from smoothschedule.communication.notifications.serializers import NotificationSerializer
        from smoothschedule.communication.notifications.models import Notification

        assert NotificationSerializer.Meta.model == Notification
