"""
Unit tests for Schedule signals.

Tests signal definitions and handler function signatures.
Signal handlers that use local imports are tested via their existence and signature.
"""
from unittest.mock import Mock, patch, MagicMock
from datetime import datetime, timedelta
import inspect
import pytest


class TestCustomSignals:
    """Test that custom signals are defined correctly."""

    def test_event_status_changed_signal_exists(self):
        """Test that event_status_changed signal is defined."""
        from smoothschedule.scheduling.schedule.signals import event_status_changed
        from django.dispatch import Signal

        assert isinstance(event_status_changed, Signal)

    def test_customer_notification_requested_signal_exists(self):
        """Test that customer_notification_requested signal is defined."""
        from smoothschedule.scheduling.schedule.signals import customer_notification_requested
        from django.dispatch import Signal

        assert isinstance(customer_notification_requested, Signal)


class TestBroadcastEventChangeSync:
    """Test broadcast_event_change_sync function."""

    def test_function_exists(self):
        """Test that broadcast function is defined."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync

        assert callable(broadcast_event_change_sync)

    def test_function_signature(self):
        """Test function accepts expected parameters."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync

        sig = inspect.signature(broadcast_event_change_sync)
        params = list(sig.parameters.keys())

        assert 'event' in params
        assert 'update_type' in params
        assert 'changed_fields' in params
        assert 'old_status' in params


class TestAutoAttachGlobalPlugins:
    """Test auto_attach_global_plugins handler."""

    def test_handler_exists(self):
        """Test that handler function exists."""
        from smoothschedule.scheduling.schedule.signals import auto_attach_global_plugins

        assert callable(auto_attach_global_plugins)

    def test_handler_signature(self):
        """Test handler accepts Django signal parameters."""
        from smoothschedule.scheduling.schedule.signals import auto_attach_global_plugins

        sig = inspect.signature(auto_attach_global_plugins)
        params = list(sig.parameters.keys())

        assert 'sender' in params
        assert 'instance' in params
        assert 'created' in params

    def test_skips_when_not_created(self):
        """Test that handler returns early when event is not new."""
        from smoothschedule.scheduling.schedule.signals import auto_attach_global_plugins

        mock_event = Mock()

        # The function checks `if not created: return`
        # We verify this by checking the function doesn't raise
        # when called with created=False (it should return immediately)
        result = auto_attach_global_plugins(sender=None, instance=mock_event, created=False)
        assert result is None


class TestTrackEventChanges:
    """Test track_event_changes pre_save handler."""

    def test_handler_exists(self):
        """Test that handler function exists."""
        from smoothschedule.scheduling.schedule.signals import track_event_changes

        assert callable(track_event_changes)

    def test_handler_signature(self):
        """Test handler accepts Django signal parameters."""
        from smoothschedule.scheduling.schedule.signals import track_event_changes

        sig = inspect.signature(track_event_changes)
        params = list(sig.parameters.keys())

        assert 'sender' in params
        assert 'instance' in params

    def test_skips_for_new_events(self):
        """Test that handler skips new events (no pk)."""
        from smoothschedule.scheduling.schedule.signals import track_event_changes

        mock_event = Mock()
        mock_event.pk = None

        # Should return early without error
        result = track_event_changes(sender=None, instance=mock_event)
        assert result is None


class TestSignalHandlerRegistration:
    """Test that signal handlers are properly registered."""

    def test_post_save_has_receivers(self):
        """Test that post_save signal has receivers."""
        from django.db.models.signals import post_save

        # Import signals module to ensure handlers are registered
        from smoothschedule.scheduling.schedule import signals  # noqa

        assert len(post_save.receivers) > 0

    def test_pre_save_has_receivers(self):
        """Test that pre_save signal has receivers."""
        from django.db.models.signals import pre_save

        # Import signals module to ensure handlers are registered
        from smoothschedule.scheduling.schedule import signals  # noqa

        assert len(pre_save.receivers) > 0


class TestEventPluginSignalHandlers:
    """Test EventPlugin-related signal handlers."""

    def test_signals_module_has_plugin_handlers(self):
        """Test that plugin-related handlers exist."""
        from smoothschedule.scheduling.schedule import signals

        # Check for any plugin-related functions
        module_functions = [name for name in dir(signals) if callable(getattr(signals, name, None))]

        # Should have functions that handle plugins
        assert len(module_functions) > 5  # Basic sanity check


class TestEventDeletionSignals:
    """Test event deletion signal handlers."""

    def test_pre_delete_has_receivers(self):
        """Test that pre_delete signal has receivers."""
        from django.db.models.signals import pre_delete

        # Import signals module to ensure handlers are registered
        from smoothschedule.scheduling.schedule import signals  # noqa

        # May or may not have receivers depending on setup
        # Just verify the signal exists
        assert pre_delete is not None


class TestBroadcastEventChangeSyncExecution:
    """Test broadcast_event_change_sync function execution."""

    @patch('channels.layers.get_channel_layer')
    def test_skips_when_no_channel_layer(self, mock_get_layer):
        """Should skip broadcast when no channel layer configured."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync

        mock_get_layer.return_value = None
        mock_event = Mock()

        # Should not raise
        broadcast_event_change_sync(mock_event, 'created')


class TestRescheduleEventPluginsOnChange:
    """Test reschedule_event_plugins_on_change handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_plugins_on_change

        assert callable(reschedule_event_plugins_on_change)

    def test_skips_for_new_events(self):
        """Should skip for newly created events."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_plugins_on_change

        mock_event = Mock()

        # Should return early for new events
        result = reschedule_event_plugins_on_change(sender=None, instance=mock_event, created=True)
        assert result is None

    def test_skips_when_no_old_values(self):
        """Should skip when no old values tracked."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_plugins_on_change

        mock_event = Mock(spec=[])  # Empty spec, no _old_start_time

        # Should return early for events without old values
        result = reschedule_event_plugins_on_change(sender=None, instance=mock_event, created=False)
        # Just verify it doesn't crash
        assert True


class TestScheduleEventPluginOnCreate:
    """Test schedule_event_plugin_on_create handler."""

    def test_handler_exists(self):
        """Test schedule_event_plugin_on_create handler exists."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_on_create

        assert callable(schedule_event_plugin_on_create)

    def test_skips_for_existing_plugins(self):
        """Should skip scheduling for updates."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_on_create

        mock_plugin = Mock()

        # created=False means update, should skip
        result = schedule_event_plugin_on_create(sender=None, instance=mock_plugin, created=False)
        assert result is None


class TestCancelEventPluginOnDelete:
    """Test cancel_event_plugin_on_delete handler."""

    def test_handler_exists(self):
        """Test cancel_event_plugin_on_delete handler exists."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_plugin_on_delete

        assert callable(cancel_event_plugin_on_delete)


class TestCancelEventTasksOnDelete:
    """Test cancel_event_tasks_on_delete handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_delete

        assert callable(cancel_event_tasks_on_delete)


class TestCancelEventTasksOnCancel:
    """Test cancel_event_tasks_on_cancel handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_cancel

        assert callable(cancel_event_tasks_on_cancel)

    def test_skips_for_new_events(self):
        """Should skip for newly created events."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_cancel

        mock_event = Mock()

        result = cancel_event_tasks_on_cancel(sender=None, instance=mock_event, created=True)
        assert result is None


class TestBroadcastEventSave:
    """Test broadcast_event_save handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_save

        assert callable(broadcast_event_save)


class TestBroadcastEventDelete:
    """Test broadcast_event_delete handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_delete

        assert callable(broadcast_event_delete)


class TestEmitStatusChange:
    """Test emit_status_change function."""

    def test_function_exists(self):
        """Test function exists."""
        from smoothschedule.scheduling.schedule.signals import emit_status_change

        assert callable(emit_status_change)


class TestHandleEventStatusChangeNotifications:
    """Test handle_event_status_change_notifications signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_notifications

        assert callable(handle_event_status_change_notifications)


class TestHandleEventStatusChangePlugins:
    """Test handle_event_status_change_plugins signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_plugins

        assert callable(handle_event_status_change_plugins)


class TestSendCustomerNotificationTask:
    """Test send_customer_notification_task signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import send_customer_notification_task

        assert callable(send_customer_notification_task)


class TestTrackTimeBlockChanges:
    """Test track_time_block_changes signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import track_time_block_changes

        assert callable(track_time_block_changes)


class TestIsNotificationsAvailable:
    """Test is_notifications_available function."""

    def test_function_exists(self):
        """Test function exists."""
        from smoothschedule.scheduling.schedule.signals import is_notifications_available

        assert callable(is_notifications_available)

    def test_returns_boolean(self):
        """Should return a boolean."""
        from smoothschedule.scheduling.schedule.signals import is_notifications_available

        result = is_notifications_available()
        assert isinstance(result, bool)


class TestCreateNotificationSafe:
    """Test create_notification_safe function."""

    def test_function_exists(self):
        """Test function exists."""
        from smoothschedule.scheduling.schedule.signals import create_notification_safe

        assert callable(create_notification_safe)


class TestNotifyManagersOnPendingTimeOff:
    """Test notify_managers_on_pending_time_off signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import notify_managers_on_pending_time_off

        assert callable(notify_managers_on_pending_time_off)


class TestSendTimeOffEmailNotifications:
    """Test send_time_off_email_notifications signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import send_time_off_email_notifications

        assert callable(send_time_off_email_notifications)


class TestApplyGlobalPluginToExistingEvents:
    """Test apply_global_plugin_to_existing_events signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import apply_global_plugin_to_existing_events

        assert callable(apply_global_plugin_to_existing_events)

    def test_skips_for_existing_rules(self):
        """Should skip for rule updates (not new)."""
        from smoothschedule.scheduling.schedule.signals import apply_global_plugin_to_existing_events

        mock_rule = Mock()

        result = apply_global_plugin_to_existing_events(sender=None, instance=mock_rule, created=False)
        assert result is None


class TestTrackEventPluginActiveChange:
    """Test track_event_plugin_active_change signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import track_event_plugin_active_change

        assert callable(track_event_plugin_active_change)


class TestTrackEventStatusChange:
    """Test track_event_status_change signal handler."""

    def test_handler_exists(self):
        """Test handler exists."""
        from smoothschedule.scheduling.schedule.signals import track_event_status_change

        assert callable(track_event_status_change)


class TestRescheduleCeleryTasks:
    """Test reschedule_event_celery_tasks function."""

    def test_function_exists(self):
        """Test function exists."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_celery_tasks

        assert callable(reschedule_event_celery_tasks)


class TestScheduleEventPluginTask:
    """Test schedule_event_plugin_task function."""

    def test_function_exists(self):
        """Test function exists."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_task

        assert callable(schedule_event_plugin_task)

    def test_function_signature(self):
        """Test function has correct signature."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_task

        sig = inspect.signature(schedule_event_plugin_task)
        params = list(sig.parameters.keys())

        assert 'event_plugin' in params
        assert 'execution_time' in params


class TestBroadcastEventChangeSyncWithLayer:
    """Test broadcast_event_change_sync with channel layer."""

    @patch('channels.layers.get_channel_layer')
    def test_skips_when_no_channel_layer(self, mock_get_layer):
        """Should skip broadcast when no channel layer configured."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync

        mock_get_layer.return_value = None
        mock_event = Mock()

        # Should not raise
        result = broadcast_event_change_sync(mock_event, 'event_created')
        # Function returns early when no channel layer
        assert result is None


class TestRescheduleEventCeleryTasksExecution:
    """Test reschedule_event_celery_tasks function execution."""

    def test_reschedules_affected_plugins(self):
        """Should reschedule plugins when timing changes."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_celery_tasks

        mock_event = Mock()
        mock_plugin = Mock()
        mock_plugin.trigger = 'before_start'
        mock_plugin.get_execution_time.return_value = datetime(2024, 1, 15, 12, 0, 0)

        mock_queryset = Mock()
        mock_queryset.__iter__ = lambda self: iter([mock_plugin])
        mock_event.event_plugins.filter.return_value = mock_queryset

        with patch('smoothschedule.scheduling.schedule.signals.schedule_event_plugin_task') as mock_schedule:
            reschedule_event_celery_tasks(mock_event, start_changed=True, end_changed=False)

            # Should have called schedule_event_plugin_task
            mock_schedule.assert_called_once()


class TestApplyGlobalPluginToExistingEventsExecution:
    """Test apply_global_plugin_to_existing_events execution paths."""

    def test_skips_inactive_rule(self):
        """Should skip when rule is inactive."""
        from smoothschedule.scheduling.schedule.signals import apply_global_plugin_to_existing_events

        mock_rule = Mock()
        mock_rule.is_active = False

        result = apply_global_plugin_to_existing_events(sender=None, instance=mock_rule, created=True)
        assert result is None

    def test_skips_when_apply_to_existing_false(self):
        """Should skip when apply_to_existing is False."""
        from smoothschedule.scheduling.schedule.signals import apply_global_plugin_to_existing_events

        mock_rule = Mock()
        mock_rule.is_active = True
        mock_rule.apply_to_existing = False

        result = apply_global_plugin_to_existing_events(sender=None, instance=mock_rule, created=True)
        assert result is None


class TestScheduleEventPluginOnCreateExecution:
    """Test schedule_event_plugin_on_create execution paths."""

    def test_skips_non_time_based_triggers(self):
        """Should skip for non-time-based triggers."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_on_create

        mock_plugin = Mock()
        mock_plugin.trigger = 'on_complete'  # Not time-based

        result = schedule_event_plugin_on_create(sender=None, instance=mock_plugin, created=True)
        assert result is None

    @patch('smoothschedule.scheduling.schedule.signals.schedule_event_plugin_task')
    def test_schedules_for_time_based_trigger(self, mock_schedule):
        """Should schedule for time-based triggers."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_on_create

        mock_plugin = Mock()
        mock_plugin.trigger = 'before_start'
        mock_plugin.is_active = True
        mock_plugin.get_execution_time.return_value = datetime(2024, 1, 15, 12, 0, 0)

        schedule_event_plugin_on_create(sender=None, instance=mock_plugin, created=True)

        mock_schedule.assert_called_once()


class TestTrackEventPluginActiveChangeExecution:
    """Test track_event_plugin_active_change execution."""

    def test_sets_was_active_for_new_plugin(self):
        """Should set _was_active to None for new plugins."""
        from smoothschedule.scheduling.schedule.signals import track_event_plugin_active_change

        mock_plugin = Mock()
        mock_plugin.pk = None

        track_event_plugin_active_change(sender=None, instance=mock_plugin)

        assert mock_plugin._was_active is None


class TestTrackEventStatusChangeExecution:
    """Test track_event_status_change execution."""

    def test_sets_old_status_for_new_event(self):
        """Should set _old_status to None for new events."""
        from smoothschedule.scheduling.schedule.signals import track_event_status_change

        mock_event = Mock()
        mock_event.pk = None

        track_event_status_change(sender=None, instance=mock_event)

        assert mock_event._old_status is None


class TestCancelEventTasksOnCancelExecution:
    """Test cancel_event_tasks_on_cancel execution."""

    def test_skips_when_not_canceled(self):
        """Should skip when status is not CANCELED."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_cancel

        mock_event = Mock()
        mock_event._old_status = 'SCHEDULED'
        mock_event.status = 'IN_PROGRESS'  # Not CANCELED

        # Should return early
        result = cancel_event_tasks_on_cancel(sender=None, instance=mock_event, created=False)
        # No crash means success for non-cancelled events


class TestEmitStatusChangeExecution:
    """Test emit_status_change function execution."""

    def test_sends_signal_with_correct_args(self):
        """Should send signal with all arguments."""
        from smoothschedule.scheduling.schedule.signals import emit_status_change, event_status_changed

        mock_event = Mock()
        mock_event.__class__ = Mock

        with patch.object(event_status_changed, 'send') as mock_send:
            emit_status_change(
                event=mock_event,
                old_status='SCHEDULED',
                new_status='COMPLETED',
                changed_by=Mock(),
                tenant=Mock(),
                skip_notifications=False
            )

            mock_send.assert_called_once()
            call_kwargs = mock_send.call_args[1]
            assert call_kwargs['event'] == mock_event
            assert call_kwargs['old_status'] == 'SCHEDULED'
            assert call_kwargs['new_status'] == 'COMPLETED'


class TestHandleEventStatusChangeNotificationsExecution:
    """Test handle_event_status_change_notifications execution."""

    def test_skips_when_notifications_disabled(self):
        """Should skip when skip_notifications is True."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_notifications

        mock_event = Mock()

        # Should not raise
        handle_event_status_change_notifications(
            sender=None,
            event=mock_event,
            old_status='SCHEDULED',
            new_status='EN_ROUTE',
            changed_by=Mock(),
            tenant=Mock(),
            skip_notifications=True
        )

    def test_handler_signature(self):
        """Should have correct parameters."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_notifications

        sig = inspect.signature(handle_event_status_change_notifications)
        params = list(sig.parameters.keys())

        assert 'event' in params
        assert 'old_status' in params
        assert 'new_status' in params
        assert 'changed_by' in params
        assert 'tenant' in params


class TestHandleEventStatusChangePluginsExecution:
    """Test handle_event_status_change_plugins execution."""

    def test_handler_exists(self):
        """Should exist as a callable."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_plugins

        assert callable(handle_event_status_change_plugins)

    def test_handler_signature(self):
        """Should have correct parameters."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_plugins

        sig = inspect.signature(handle_event_status_change_plugins)
        params = list(sig.parameters.keys())

        assert 'event' in params
        assert 'old_status' in params
        assert 'new_status' in params


class TestSendCustomerNotificationTaskExecution:
    """Test send_customer_notification_task execution."""

    def test_handler_exists(self):
        """Should exist as a callable."""
        from smoothschedule.scheduling.schedule.signals import send_customer_notification_task

        assert callable(send_customer_notification_task)

    def test_handler_signature(self):
        """Should have correct parameters."""
        from smoothschedule.scheduling.schedule.signals import send_customer_notification_task

        sig = inspect.signature(send_customer_notification_task)
        params = list(sig.parameters.keys())

        assert 'event' in params
        assert 'notification_type' in params
        assert 'tenant' in params


class TestTrackTimeBlockChangesExecution:
    """Test track_time_block_changes execution."""

    def test_sets_defaults_for_new_block(self):
        """Should set default values for new time blocks."""
        from smoothschedule.scheduling.schedule.signals import track_time_block_changes

        mock_block = Mock()
        mock_block.pk = None

        track_time_block_changes(sender=None, instance=mock_block)

        assert mock_block._needs_re_approval_notification is False
        assert mock_block._old_approval_status is None
        assert mock_block._was_approved is False
        assert mock_block._changed_fields == []


class TestCreateNotificationSafeExecution:
    """Test create_notification_safe function execution."""

    @patch('smoothschedule.scheduling.schedule.signals.is_notifications_available')
    def test_returns_none_when_notifications_unavailable(self, mock_is_available):
        """Should return None when notifications not available."""
        from smoothschedule.scheduling.schedule.signals import create_notification_safe

        mock_is_available.return_value = False

        result = create_notification_safe(
            recipient=Mock(),
            actor=Mock(),
            verb='test'
        )

        assert result is None


class TestTimeBlockApprovalFields:
    """Test TIME_BLOCK_APPROVAL_FIELDS constant."""

    def test_approval_fields_defined(self):
        """Should have approval fields defined."""
        from smoothschedule.scheduling.schedule.signals import TIME_BLOCK_APPROVAL_FIELDS

        assert isinstance(TIME_BLOCK_APPROVAL_FIELDS, list)
        assert len(TIME_BLOCK_APPROVAL_FIELDS) > 0
        assert 'title' in TIME_BLOCK_APPROVAL_FIELDS
        assert 'start_date' in TIME_BLOCK_APPROVAL_FIELDS
        assert 'end_date' in TIME_BLOCK_APPROVAL_FIELDS


class TestTimeOffRequestSubmittedSignal:
    """Test time_off_request_submitted signal."""

    def test_signal_exists(self):
        """Test signal is defined."""
        from smoothschedule.scheduling.schedule.signals import time_off_request_submitted
        from django.dispatch import Signal

        assert isinstance(time_off_request_submitted, Signal)


class TestBroadcastEventChangeSyncExecution:
    """Tests for broadcast_event_change_sync function."""

    def test_function_exists(self):
        """Should have broadcast_event_change_sync function."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync

        assert callable(broadcast_event_change_sync)

    def test_has_expected_signature(self):
        """Should have expected function signature."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_change_sync
        import inspect

        sig = inspect.signature(broadcast_event_change_sync)
        params = list(sig.parameters.keys())

        assert 'event' in params
        assert 'update_type' in params


class TestAutoAttachGlobalPluginsSignal:
    """Tests for auto_attach_global_plugins signal handler."""

    def test_function_exists(self):
        """Should have auto_attach_global_plugins function."""
        from smoothschedule.scheduling.schedule.signals import auto_attach_global_plugins

        assert callable(auto_attach_global_plugins)


class TestTrackEventChangesSignal:
    """Tests for track_event_changes signal handler."""

    def test_function_exists(self):
        """Should have track_event_changes function."""
        from smoothschedule.scheduling.schedule.signals import track_event_changes

        assert callable(track_event_changes)

    def test_has_expected_signature(self):
        """Should have expected function signature."""
        from smoothschedule.scheduling.schedule.signals import track_event_changes
        import inspect

        sig = inspect.signature(track_event_changes)
        params = list(sig.parameters.keys())

        assert 'sender' in params
        assert 'instance' in params


class TestRescheduleEventPluginsOnChangeSignal:
    """Tests for reschedule_event_plugins_on_change signal handler."""

    def test_function_exists(self):
        """Should have reschedule_event_plugins_on_change function."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_plugins_on_change

        assert callable(reschedule_event_plugins_on_change)


class TestRescheduleEventCeleryTasksFunction:
    """Tests for reschedule_event_celery_tasks function."""

    def test_function_exists(self):
        """Should have reschedule_event_celery_tasks function."""
        from smoothschedule.scheduling.schedule.signals import reschedule_event_celery_tasks

        assert callable(reschedule_event_celery_tasks)


class TestScheduleEventPluginTaskFunction:
    """Tests for schedule_event_plugin_task function."""

    def test_function_exists(self):
        """Should have schedule_event_plugin_task function."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_task

        assert callable(schedule_event_plugin_task)


class TestApplyGlobalPluginToExistingEventsSignal:
    """Tests for apply_global_plugin_to_existing_events signal handler."""

    def test_function_exists(self):
        """Should have apply_global_plugin_to_existing_events function."""
        from smoothschedule.scheduling.schedule.signals import apply_global_plugin_to_existing_events

        assert callable(apply_global_plugin_to_existing_events)


class TestScheduleEventPluginOnCreateSignal:
    """Tests for schedule_event_plugin_on_create signal handler."""

    def test_function_exists(self):
        """Should have schedule_event_plugin_on_create function."""
        from smoothschedule.scheduling.schedule.signals import schedule_event_plugin_on_create

        assert callable(schedule_event_plugin_on_create)


class TestTrackEventPluginActiveChangeSignal:
    """Tests for track_event_plugin_active_change signal handler."""

    def test_function_exists(self):
        """Should have track_event_plugin_active_change function."""
        from smoothschedule.scheduling.schedule.signals import track_event_plugin_active_change

        assert callable(track_event_plugin_active_change)


class TestCancelEventPluginOnDeleteSignal:
    """Tests for cancel_event_plugin_on_delete signal handler."""

    def test_function_exists(self):
        """Should have cancel_event_plugin_on_delete function."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_plugin_on_delete

        assert callable(cancel_event_plugin_on_delete)


class TestCancelEventTasksOnDeleteSignal:
    """Tests for cancel_event_tasks_on_delete signal handler."""

    def test_function_exists(self):
        """Should have cancel_event_tasks_on_delete function."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_delete

        assert callable(cancel_event_tasks_on_delete)


class TestTrackEventStatusChangeSignal:
    """Tests for track_event_status_change signal handler."""

    def test_function_exists(self):
        """Should have track_event_status_change function."""
        from smoothschedule.scheduling.schedule.signals import track_event_status_change

        assert callable(track_event_status_change)

    def test_has_expected_signature(self):
        """Should have expected function signature."""
        from smoothschedule.scheduling.schedule.signals import track_event_status_change
        import inspect

        sig = inspect.signature(track_event_status_change)
        params = list(sig.parameters.keys())

        assert 'sender' in params
        assert 'instance' in params


class TestCancelEventTasksOnCancelSignal:
    """Tests for cancel_event_tasks_on_cancel signal handler."""

    def test_function_exists(self):
        """Should have cancel_event_tasks_on_cancel function."""
        from smoothschedule.scheduling.schedule.signals import cancel_event_tasks_on_cancel

        assert callable(cancel_event_tasks_on_cancel)


class TestBroadcastEventSaveSignal:
    """Tests for broadcast_event_save signal handler."""

    def test_function_exists(self):
        """Should have broadcast_event_save function."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_save

        assert callable(broadcast_event_save)


class TestBroadcastEventDeleteSignal:
    """Tests for broadcast_event_delete signal handler."""

    def test_function_exists(self):
        """Should have broadcast_event_delete function."""
        from smoothschedule.scheduling.schedule.signals import broadcast_event_delete

        assert callable(broadcast_event_delete)


class TestHandleEventStatusChangeNotificationsSignal:
    """Tests for handle_event_status_change_notifications signal handler."""

    def test_function_exists(self):
        """Should have handle_event_status_change_notifications function."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_notifications

        assert callable(handle_event_status_change_notifications)


class TestHandleEventStatusChangePluginsSignal:
    """Tests for handle_event_status_change_plugins signal handler."""

    def test_function_exists(self):
        """Should have handle_event_status_change_plugins function."""
        from smoothschedule.scheduling.schedule.signals import handle_event_status_change_plugins

        assert callable(handle_event_status_change_plugins)


class TestSendCustomerNotificationTaskSignal:
    """Tests for send_customer_notification_task signal handler."""

    def test_function_exists(self):
        """Should have send_customer_notification_task function."""
        from smoothschedule.scheduling.schedule.signals import send_customer_notification_task

        assert callable(send_customer_notification_task)


class TestEmitStatusChangeFunction:
    """Tests for emit_status_change function."""

    def test_function_exists(self):
        """Should have emit_status_change function."""
        from smoothschedule.scheduling.schedule.signals import emit_status_change

        assert callable(emit_status_change)


class TestIsNotificationsAvailableFunction:
    """Tests for is_notifications_available function."""

    def test_function_exists(self):
        """Should have is_notifications_available function."""
        from smoothschedule.scheduling.schedule.signals import is_notifications_available

        assert callable(is_notifications_available)

    def test_returns_bool(self):
        """Should return a boolean."""
        from smoothschedule.scheduling.schedule.signals import is_notifications_available

        result = is_notifications_available()

        assert isinstance(result, bool)


class TestNotifyManagersOnPendingTimeOffSignal:
    """Tests for notify_managers_on_pending_time_off signal handler."""

    def test_function_exists(self):
        """Should have notify_managers_on_pending_time_off function."""
        from smoothschedule.scheduling.schedule.signals import notify_managers_on_pending_time_off

        assert callable(notify_managers_on_pending_time_off)


class TestSendTimeOffEmailNotificationsSignal:
    """Tests for send_time_off_email_notifications signal handler."""

    def test_function_exists(self):
        """Should have send_time_off_email_notifications function."""
        from smoothschedule.scheduling.schedule.signals import send_time_off_email_notifications

        assert callable(send_time_off_email_notifications)
