"""
Unit tests for identity/core/signals.py

Tests tenant creation signal handlers.
"""

from unittest.mock import Mock, patch, MagicMock

import pytest

from smoothschedule.identity.core.signals import (
    _seed_plugins_for_tenant,
    seed_platform_plugins_on_tenant_create,
)


class TestSeedPluginsForTenant:
    """Tests for _seed_plugins_for_tenant function."""

    @patch('django_tenants.utils.schema_context')
    @patch('smoothschedule.identity.core.signals.logger')
    def test_logs_start_of_seeding(self, mock_logger, mock_schema_context):
        """Should log when starting to seed plugins."""
        mock_schema_context.return_value.__enter__ = Mock()
        mock_schema_context.return_value.__exit__ = Mock(return_value=False)

        with patch('smoothschedule.scheduling.schedule.models.PluginTemplate') as mock_pt:
            mock_pt.objects.filter.return_value.exists.return_value = True

            with patch(
                'smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins.get_platform_plugins',
                return_value=[]
            ):
                _seed_plugins_for_tenant('test_schema')

        mock_logger.info.assert_called()

    @patch('django_tenants.utils.schema_context')
    @patch('django.utils.timezone')
    def test_creates_plugins_that_dont_exist(self, mock_tz, mock_schema_context):
        """Should create plugins that don't already exist."""
        mock_schema_context.return_value.__enter__ = Mock()
        mock_schema_context.return_value.__exit__ = Mock(return_value=False)
        mock_tz.now.return_value = 'mock_time'

        plugin_data = {
            'name': 'Test Plugin',
            'slug': 'test-plugin',
            'category': 'TEST',
            'short_description': 'A test plugin',
            'description': 'Full description',
            'plugin_code': 'print("test")',
            'logo_url': 'http://example.com/logo.png',
        }

        with patch('smoothschedule.scheduling.schedule.models.PluginTemplate') as mock_pt:
            mock_pt.objects.filter.return_value.exists.return_value = False
            mock_pt.Visibility.PLATFORM = 'PLATFORM'

            with patch(
                'smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins.get_platform_plugins',
                return_value=[plugin_data]
            ):
                _seed_plugins_for_tenant('test_schema')

            mock_pt.objects.create.assert_called_once()
            call_kwargs = mock_pt.objects.create.call_args[1]
            assert call_kwargs['name'] == 'Test Plugin'
            assert call_kwargs['slug'] == 'test-plugin'
            assert call_kwargs['is_approved'] is True

    @patch('django_tenants.utils.schema_context')
    def test_skips_existing_plugins(self, mock_schema_context):
        """Should skip plugins that already exist."""
        mock_schema_context.return_value.__enter__ = Mock()
        mock_schema_context.return_value.__exit__ = Mock(return_value=False)

        plugin_data = {
            'name': 'Existing Plugin',
            'slug': 'existing-plugin',
            'category': 'TEST',
            'short_description': 'Exists',
            'description': 'Already exists',
            'plugin_code': 'pass',
        }

        with patch('smoothschedule.scheduling.schedule.models.PluginTemplate') as mock_pt:
            mock_pt.objects.filter.return_value.exists.return_value = True

            with patch(
                'smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins.get_platform_plugins',
                return_value=[plugin_data]
            ):
                _seed_plugins_for_tenant('test_schema')

            mock_pt.objects.create.assert_not_called()

    @patch('django_tenants.utils.schema_context')
    @patch('smoothschedule.identity.core.signals.logger')
    def test_logs_error_on_exception(self, mock_logger, mock_schema_context):
        """Should log error when exception occurs."""
        mock_schema_context.side_effect = Exception("Test error")

        _seed_plugins_for_tenant('test_schema')

        mock_logger.error.assert_called()

    @patch('django_tenants.utils.schema_context')
    @patch('django.utils.timezone')
    def test_handles_missing_logo_url(self, mock_tz, mock_schema_context):
        """Should handle plugin data without logo_url."""
        mock_schema_context.return_value.__enter__ = Mock()
        mock_schema_context.return_value.__exit__ = Mock(return_value=False)
        mock_tz.now.return_value = 'mock_time'

        plugin_data = {
            'name': 'No Logo Plugin',
            'slug': 'no-logo',
            'category': 'TEST',
            'short_description': 'No logo',
            'description': 'No logo URL',
            'plugin_code': 'pass',
            # No logo_url
        }

        with patch('smoothschedule.scheduling.schedule.models.PluginTemplate') as mock_pt:
            mock_pt.objects.filter.return_value.exists.return_value = False
            mock_pt.Visibility.PLATFORM = 'PLATFORM'

            with patch(
                'smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins.get_platform_plugins',
                return_value=[plugin_data]
            ):
                _seed_plugins_for_tenant('test_schema')

            call_kwargs = mock_pt.objects.create.call_args[1]
            assert call_kwargs['logo_url'] == ''

    @patch('django_tenants.utils.schema_context')
    @patch('smoothschedule.identity.core.signals.logger')
    def test_logs_created_count(self, mock_logger, mock_schema_context):
        """Should log the number of plugins created."""
        mock_schema_context.return_value.__enter__ = Mock()
        mock_schema_context.return_value.__exit__ = Mock(return_value=False)

        with patch('smoothschedule.scheduling.schedule.models.PluginTemplate') as mock_pt:
            mock_pt.objects.filter.return_value.exists.return_value = False
            mock_pt.Visibility.PLATFORM = 'PLATFORM'

            with patch(
                'smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins.get_platform_plugins',
                return_value=[
                    {'name': 'P1', 'slug': 's1', 'category': 'C', 'short_description': '', 'description': '', 'plugin_code': ''},
                    {'name': 'P2', 'slug': 's2', 'category': 'C', 'short_description': '', 'description': '', 'plugin_code': ''},
                ]
            ):
                with patch('django.utils.timezone'):
                    _seed_plugins_for_tenant('test_schema')

        # Should log info with created count
        info_calls = [str(call) for call in mock_logger.info.call_args_list]
        assert any('2' in str(call) for call in info_calls)


class TestSeedPlatformPluginsOnTenantCreate:
    """Tests for seed_platform_plugins_on_tenant_create signal handler."""

    @patch('smoothschedule.identity.core.signals.transaction')
    def test_schedules_seeding_on_commit(self, mock_transaction):
        """Should schedule plugin seeding on transaction commit."""
        instance = Mock()
        instance.schema_name = 'tenant_schema'

        seed_platform_plugins_on_tenant_create(Mock(), instance, created=True)

        mock_transaction.on_commit.assert_called_once()

    @patch('smoothschedule.identity.core.signals.transaction')
    def test_does_not_trigger_on_update(self, mock_transaction):
        """Should not trigger when tenant is updated (not created)."""
        instance = Mock()
        instance.schema_name = 'tenant_schema'

        seed_platform_plugins_on_tenant_create(Mock(), instance, created=False)

        mock_transaction.on_commit.assert_not_called()

    @patch('smoothschedule.identity.core.signals.transaction')
    def test_does_not_trigger_for_public_schema(self, mock_transaction):
        """Should not trigger for public schema."""
        instance = Mock()
        instance.schema_name = 'public'

        seed_platform_plugins_on_tenant_create(Mock(), instance, created=True)

        mock_transaction.on_commit.assert_not_called()

    @patch('smoothschedule.identity.core.signals.transaction')
    @patch('smoothschedule.identity.core.signals._seed_plugins_for_tenant')
    def test_on_commit_calls_seed_function(self, mock_seed, mock_transaction):
        """Should call _seed_plugins_for_tenant when transaction commits."""
        instance = Mock()
        instance.schema_name = 'new_tenant'

        # Capture the callback passed to on_commit
        def capture_callback(callback):
            callback()

        mock_transaction.on_commit.side_effect = capture_callback

        seed_platform_plugins_on_tenant_create(Mock(), instance, created=True)

        mock_seed.assert_called_once_with('new_tenant')
