"""
Unit tests for notifications models.
"""
from datetime import datetime
from unittest.mock import Mock, MagicMock
import pytest


class TestNotificationModel:
    """Unit tests for the Notification model."""

    def test_notification_str_method(self):
        """Test the __str__ method returns correct format."""
        # Arrange
        from smoothschedule.communication.notifications.models import Notification

        mock_user = Mock()
        mock_user.email = "user@example.com"

        mock_timestamp = Mock()
        mock_timestamp.strftime.return_value = "2024-01-15 14:30"

        # Create an instance with mocked attributes
        notification = Mock(spec=Notification)
        notification.recipient = mock_user
        notification.verb = "assigned you to a task"
        notification.timestamp = mock_timestamp

        # Use the actual __str__ implementation
        result = Notification.__str__(notification)

        # Assert
        assert result == "user@example.com - assigned you to a task - 2024-01-15 14:30"
        mock_timestamp.strftime.assert_called_once_with('%Y-%m-%d %H:%M')

    def test_notification_default_read_status(self):
        """Test that notifications default to unread."""
        # Arrange
        notification = MagicMock()
        notification.read = False

        # Assert
        assert notification.read is False

    def test_notification_default_data_field(self):
        """Test that data field defaults to empty dict."""
        # Arrange
        notification = MagicMock()
        notification.data = {}

        # Assert
        assert notification.data == {}

    def test_notification_with_actor(self):
        """Test notification with an actor object."""
        # Arrange
        mock_actor = Mock()
        mock_actor.full_name = "John Doe"
        mock_actor.email = "john@example.com"

        mock_user = Mock()
        mock_user.email = "recipient@example.com"

        notification = MagicMock()
        notification.recipient = mock_user
        notification.actor = mock_actor
        notification.verb = "assigned you to a ticket"

        # Assert
        assert notification.actor.full_name == "John Doe"
        assert notification.actor.email == "john@example.com"

    def test_notification_without_actor(self):
        """Test notification without an actor (system notification)."""
        # Arrange
        mock_user = Mock()
        mock_user.email = "recipient@example.com"

        notification = MagicMock()
        notification.recipient = mock_user
        notification.actor = None
        notification.verb = "your appointment is starting soon"

        # Assert
        assert notification.actor is None

    def test_notification_with_target_object(self):
        """Test notification with a target object."""
        # Arrange
        mock_target = Mock()
        mock_target.subject = "Urgent: Server Down"
        mock_target.id = 42

        notification = MagicMock()
        notification.target = mock_target
        notification.target_object_id = "42"

        # Assert
        assert notification.target.subject == "Urgent: Server Down"
        assert notification.target_object_id == "42"

    def test_notification_with_action_object(self):
        """Test notification with an action object."""
        # Arrange
        mock_action = Mock()
        mock_action.content = "This is a comment"

        notification = MagicMock()
        notification.action_object = mock_action

        # Assert
        assert notification.action_object.content == "This is a comment"

    def test_notification_with_extra_data(self):
        """Test notification with extra JSON data."""
        # Arrange
        extra_data = {
            'previous_status': 'pending',
            'new_status': 'in_progress',
            'link': '/tickets/42'
        }

        notification = MagicMock()
        notification.data = extra_data

        # Assert
        assert notification.data['previous_status'] == 'pending'
        assert notification.data['new_status'] == 'in_progress'
        assert notification.data['link'] == '/tickets/42'

    def test_notification_ordering(self):
        """Test that notifications are ordered by timestamp descending."""
        # This verifies the Meta.ordering configuration
        from smoothschedule.communication.notifications.models import Notification

        # Assert
        assert Notification._meta.ordering == ['-timestamp']

    def test_notification_indexes(self):
        """Test that proper database indexes are configured."""
        from smoothschedule.communication.notifications.models import Notification

        # Get the indexes
        indexes = Notification._meta.indexes

        # Assert - should have 2 indexes
        assert len(indexes) == 2

        # Verify index fields
        index_fields = [tuple(idx.fields) for idx in indexes]
        assert ('recipient', 'read', 'timestamp') in index_fields
        assert ('recipient', 'timestamp') in index_fields

    def test_notification_cascade_delete_on_user(self):
        """Test that notifications are deleted when user is deleted."""
        from smoothschedule.communication.notifications.models import Notification
        from django.db.models import CASCADE

        # Get the recipient field
        recipient_field = Notification._meta.get_field('recipient')

        # Assert
        assert recipient_field.remote_field.on_delete == CASCADE

    def test_notification_content_type_fields(self):
        """Test that content type fields allow null/blank."""
        from smoothschedule.communication.notifications.models import Notification

        # Actor content type
        actor_ct = Notification._meta.get_field('actor_content_type')
        assert actor_ct.null is True
        assert actor_ct.blank is True

        # Action object content type
        action_ct = Notification._meta.get_field('action_object_content_type')
        assert action_ct.null is True
        assert action_ct.blank is True

        # Target content type
        target_ct = Notification._meta.get_field('target_content_type')
        assert target_ct.null is True
        assert target_ct.blank is True

    def test_notification_generic_fk_fields_allow_null(self):
        """Test that generic foreign key ID fields allow null."""
        from smoothschedule.communication.notifications.models import Notification

        # Actor object ID
        actor_id = Notification._meta.get_field('actor_object_id')
        assert actor_id.null is True
        assert actor_id.blank is True

        # Action object ID
        action_id = Notification._meta.get_field('action_object_object_id')
        assert action_id.null is True
        assert action_id.blank is True

        # Target object ID
        target_id = Notification._meta.get_field('target_object_id')
        assert target_id.null is True
        assert target_id.blank is True

    def test_notification_verb_max_length(self):
        """Test that verb field has proper max_length."""
        from smoothschedule.communication.notifications.models import Notification

        verb_field = Notification._meta.get_field('verb')

        assert verb_field.max_length == 255

    def test_notification_timestamp_auto_now_add(self):
        """Test that timestamp is set automatically on creation."""
        from smoothschedule.communication.notifications.models import Notification

        timestamp_field = Notification._meta.get_field('timestamp')

        assert timestamp_field.auto_now_add is True

    def test_notification_related_names(self):
        """Test that related names are properly configured."""
        from smoothschedule.communication.notifications.models import Notification

        # User recipient field
        recipient_field = Notification._meta.get_field('recipient')
        assert recipient_field.remote_field.related_name == 'notifications'

        # Actor content type
        actor_ct = Notification._meta.get_field('actor_content_type')
        assert actor_ct.remote_field.related_name == 'notifications_as_actor'

        # Action object content type
        action_ct = Notification._meta.get_field('action_object_content_type')
        assert action_ct.remote_field.related_name == 'notifications_as_action_object'

        # Target content type
        target_ct = Notification._meta.get_field('target_content_type')
        assert target_ct.remote_field.related_name == 'notifications_as_target'
