"""
Unit tests for Schedule ViewSets.

Tests viewset methods and actions with mocks to avoid database access.
"""
from unittest.mock import Mock, patch, MagicMock
from rest_framework.test import APIRequestFactory
from rest_framework import status
import pytest


class TestResourceTypeViewSetDestroy:
    """Test ResourceTypeViewSet.destroy method."""

    def test_destroy_blocks_default_types(self):
        """Test that default resource types cannot be deleted."""
        from smoothschedule.scheduling.schedule.views import ResourceTypeViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.delete('/api/resource-types/1/')
        request.user = Mock(is_authenticated=True)

        # Create mock instance
        mock_instance = Mock()
        mock_instance.is_default = True
        mock_instance.name = 'Staff'

        # Create viewset and patch get_object
        viewset = ResourceTypeViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {'pk': 1}

        with patch.object(viewset, 'get_object', return_value=mock_instance):
            response = viewset.destroy(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'Cannot delete default' in response.data['error']

    def test_destroy_blocks_types_in_use(self):
        """Test that resource types in use cannot be deleted."""
        from smoothschedule.scheduling.schedule.views import ResourceTypeViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.delete('/api/resource-types/1/')
        request.user = Mock(is_authenticated=True)

        # Create mock instance with resources
        mock_instance = Mock()
        mock_instance.is_default = False
        mock_instance.name = 'Custom Type'
        mock_instance.resources.exists.return_value = True
        mock_instance.resources.count.return_value = 5

        viewset = ResourceTypeViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {'pk': 1}

        with patch.object(viewset, 'get_object', return_value=mock_instance):
            response = viewset.destroy(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'in use by 5 resource(s)' in response.data['error']

    def test_destroy_allows_unused_custom_types(self):
        """Test that unused custom types can be deleted."""
        from smoothschedule.scheduling.schedule.views import ResourceTypeViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.delete('/api/resource-types/1/')
        request.user = Mock(is_authenticated=True)

        mock_instance = Mock()
        mock_instance.is_default = False
        mock_instance.name = 'Unused Type'
        mock_instance.resources.exists.return_value = False

        viewset = ResourceTypeViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {'pk': 1}

        with patch.object(viewset, 'get_object', return_value=mock_instance):
            with patch.object(ResourceTypeViewSet, 'destroy', wraps=viewset.destroy) as mock_destroy:
                # Call the parent destroy (which would do the actual delete)
                # We just verify our validation passed
                with patch('rest_framework.mixins.DestroyModelMixin.destroy') as parent_destroy:
                    parent_destroy.return_value = Mock(status_code=204)
                    response = viewset.destroy(request)

        # Assert - should reach parent destroy (204 No Content)
        assert response.status_code == 204


class TestResourceViewSetLocation:
    """Test ResourceViewSet.location action."""

    def test_location_returns_error_when_resource_has_no_user(self):
        """Test location action when resource has no linked user."""
        from smoothschedule.scheduling.schedule.views import ResourceViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/api/resources/1/location/')
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')
        request.tenant = Mock()

        mock_resource = Mock()
        mock_resource.user = None

        viewset = ResourceViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {'pk': 1}

        with patch.object(viewset, 'get_object', return_value=mock_resource):
            response = viewset.location(request, pk=1)

        # Assert
        assert response.data['has_location'] is False
        assert 'no linked user' in response.data['message']

    def test_location_returns_error_when_no_tenant(self):
        """Test location action when no tenant context."""
        from smoothschedule.scheduling.schedule.views import ResourceViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/api/resources/1/location/')
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')
        request.tenant = None

        mock_resource = Mock()
        mock_resource.user = Mock(id=1)

        viewset = ResourceViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {'pk': 1}

        with patch.object(viewset, 'get_object', return_value=mock_resource):
            response = viewset.location(request, pk=1)

        # Assert
        assert response.data['has_location'] is False
        assert 'No tenant context' in response.data['message']


class TestServiceViewSet:
    """Test ServiceViewSet."""

    def test_get_queryset_filters_active_only(self):
        """Test that get_queryset returns only active services by default."""
        from smoothschedule.scheduling.schedule.views import ServiceViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/api/services/')
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')
        request.tenant = Mock()

        viewset = ServiceViewSet()
        viewset.request = request
        viewset.action = 'list'

        # The actual filtering is done via TenantFilteredQuerySetMixin
        # We just verify the viewset has correct configuration
        assert hasattr(viewset, 'permission_classes')


class TestEventViewSetActions:
    """Test EventViewSet custom actions."""

    def test_viewset_exists(self):
        """Test that EventViewSet is properly configured."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Verify the viewset exists and has basic configuration
        assert hasattr(EventViewSet, 'queryset')
        assert hasattr(EventViewSet, 'serializer_class')


class TestTimeBlockViewSet:
    """Test TimeBlockViewSet."""

    def test_viewset_has_blocked_dates_action(self):
        """Test that blocked_dates action exists."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        assert hasattr(TimeBlockViewSet, 'blocked_dates')

    def test_viewset_has_check_conflicts_action(self):
        """Test that check_conflicts action exists."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        assert hasattr(TimeBlockViewSet, 'check_conflicts')


class TestCustomerViewSet:
    """Test CustomerViewSet."""

    def test_uses_user_tenant_filtered_mixin(self):
        """Test that CustomerViewSet uses UserTenantFilteredMixin."""
        from smoothschedule.scheduling.schedule.views import CustomerViewSet
        from smoothschedule.identity.core.mixins import UserTenantFilteredMixin

        assert issubclass(CustomerViewSet, UserTenantFilteredMixin)

    def test_uses_deny_staff_list_permission(self):
        """Test that CustomerViewSet uses DenyStaffListPermission."""
        from smoothschedule.scheduling.schedule.views import CustomerViewSet
        from smoothschedule.identity.core.mixins import DenyStaffListPermission

        assert DenyStaffListPermission in CustomerViewSet.permission_classes


class TestStaffViewSet:
    """Test StaffViewSet."""

    def test_uses_user_tenant_filtered_mixin(self):
        """Test that StaffViewSet uses UserTenantFilteredMixin."""
        from smoothschedule.scheduling.schedule.views import StaffViewSet
        from smoothschedule.identity.core.mixins import UserTenantFilteredMixin

        assert issubclass(StaffViewSet, UserTenantFilteredMixin)


class TestPluginViewSets:
    """Test plugin-related viewsets."""

    def test_plugin_template_viewset_exists(self):
        """Test that PluginTemplateViewSet is properly configured."""
        from smoothschedule.scheduling.schedule.views import PluginTemplateViewSet

        assert hasattr(PluginTemplateViewSet, 'queryset')
        assert hasattr(PluginTemplateViewSet, 'serializer_class')

    def test_scheduled_task_viewset_uses_task_feature_mixin(self):
        """Test that ScheduledTaskViewSet uses TaskFeatureRequiredMixin."""
        from smoothschedule.scheduling.schedule.views import ScheduledTaskViewSet
        from smoothschedule.identity.core.mixins import TaskFeatureRequiredMixin

        assert issubclass(ScheduledTaskViewSet, TaskFeatureRequiredMixin)


class TestEventViewSetCreate:
    """Test EventViewSet.perform_create method."""

    def test_perform_create_sets_created_by(self):
        """Test that perform_create sets created_by to request user."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/events/', {})
        mock_user = Mock(id=1, username='testuser')
        request.user = mock_user
        request.tenant = Mock()

        viewset = EventViewSet()
        viewset.request = request

        mock_serializer = Mock()

        # Act
        viewset.perform_create(mock_serializer)

        # Assert
        mock_serializer.save.assert_called_once_with(created_by=mock_user)


class TestEventViewSetUpdate:
    """Test EventViewSet.perform_update method."""

    def test_perform_update_calls_save(self):
        """Test that perform_update calls serializer.save()."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.patch('/api/events/1/', {})
        request.user = Mock()
        request.tenant = Mock()

        viewset = EventViewSet()
        viewset.request = request

        mock_serializer = Mock()

        # Act
        viewset.perform_update(mock_serializer)

        # Assert
        mock_serializer.save.assert_called_once()


class TestEventViewSetSetStatus:
    """Test EventViewSet.set_status action."""

    def test_set_status_requires_tenant_context(self):
        """Test that set_status returns error when no tenant context."""
        from smoothschedule.scheduling.schedule.views import EventViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.post('/api/events/1/set_status/', {'status': 'IN_PROGRESS'}, format='json')
        request = Request(django_request)
        request.user = Mock()
        request.tenant = None

        mock_event = Mock()

        viewset = EventViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        with patch.object(viewset, 'get_object', return_value=mock_event):
            response = viewset.set_status(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant context' in response.data['error']

    def test_set_status_requires_status_field(self):
        """Test that set_status returns error when status field missing."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/events/1/set_status/', {}, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {}
        request.user = Mock()
        request.tenant = Mock()

        mock_event = Mock()

        viewset = EventViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        with patch.object(viewset, 'get_object', return_value=mock_event):
            response = viewset.set_status(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'status is required' in response.data['error']

    def test_set_status_handles_transition_error(self):
        """Test that set_status returns error when transition fails."""
        from smoothschedule.scheduling.schedule.views import EventViewSet
        from smoothschedule.communication.mobile.services.status_machine import StatusTransitionError

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/events/1/set_status/', {'status': 'COMPLETED'}, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {'status': 'COMPLETED'}
        request.user = Mock()
        request.tenant = Mock()

        mock_event = Mock()

        viewset = EventViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        with patch.object(viewset, 'get_object', return_value=mock_event):
            # Patch at the import source, not the views module
            with patch('smoothschedule.communication.mobile.services.StatusMachine') as mock_machine:
                mock_machine.return_value.transition.side_effect = StatusTransitionError('Invalid transition')
                response = viewset.set_status(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'Invalid transition' in response.data['error']


class TestEventViewSetStartEnRoute:
    """Test EventViewSet.start_en_route action."""

    def test_start_en_route_requires_tenant_context(self):
        """Test that start_en_route returns error when no tenant context."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/events/1/start_en_route/', {})
        request.user = Mock()
        request.tenant = None

        mock_event = Mock()

        viewset = EventViewSet()
        viewset.request = request

        with patch.object(viewset, 'get_object', return_value=mock_event):
            response = viewset.start_en_route(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant context' in response.data['error']


class TestEventViewSetStatusHistory:
    """Test EventViewSet.status_history action."""

    def test_status_history_requires_tenant_context(self):
        """Test that status_history returns error when no tenant context."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/api/events/1/status_history/')
        request.user = Mock()
        request.tenant = None

        mock_event = Mock(id=1)

        viewset = EventViewSet()
        viewset.request = request

        with patch.object(viewset, 'get_object', return_value=mock_event):
            response = viewset.status_history(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant context' in response.data['error']


class TestEventViewSetAllowedTransitions:
    """Test EventViewSet.allowed_transitions action."""

    def test_allowed_transitions_requires_tenant_context(self):
        """Test that allowed_transitions returns error when no tenant context."""
        from smoothschedule.scheduling.schedule.views import EventViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/api/events/1/allowed_transitions/')
        request.user = Mock()
        request.tenant = None

        mock_event = Mock(id=1)

        viewset = EventViewSet()
        viewset.request = request

        with patch.object(viewset, 'get_object', return_value=mock_event):
            response = viewset.allowed_transitions(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant context' in response.data['error']


class TestServiceViewSetReorder:
    """Test ServiceViewSet.reorder action."""

    def test_reorder_requires_list_parameter(self):
        """Test that reorder validates order parameter is a list."""
        from smoothschedule.scheduling.schedule.views import ServiceViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/services/reorder/', {'order': 'not-a-list'}, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {'order': 'not-a-list'}
        request.user = Mock()
        request.tenant = Mock()

        viewset = ServiceViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Act
        response = viewset.reorder(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'must be a list' in response.data['error']

    def test_reorder_updates_display_order(self):
        """Test that reorder updates service display_order."""
        from smoothschedule.scheduling.schedule.views import ServiceViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/services/reorder/', {'order': [3, 1, 2]}, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {'order': [3, 1, 2]}
        request.user = Mock()
        request.tenant = Mock()

        viewset = ServiceViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Mock the Service model's filter method
        with patch('smoothschedule.scheduling.schedule.views.Service') as mock_service:
            mock_queryset = Mock()
            mock_service.objects.filter.return_value = mock_queryset

            # Act
            response = viewset.reorder(request)

            # Assert
            assert response.status_code == status.HTTP_200_OK
            assert response.data['updated'] == 3
            # Verify filter was called for each ID
            assert mock_service.objects.filter.call_count == 3


class TestServiceViewSetFilterQueryset:
    """Test ServiceViewSet.filter_queryset_for_tenant method."""

    def test_filters_active_services_by_default(self):
        """Test that only active services are shown by default."""
        from smoothschedule.scheduling.schedule.views import ServiceViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/services/')
        request = Request(django_request)
        request.user = Mock()
        request.tenant = Mock()

        viewset = ServiceViewSet()
        viewset.request = request
        viewset.action = 'list'

        mock_queryset = Mock()
        mock_queryset.filter.return_value = mock_queryset

        # Act
        result = viewset.filter_queryset_for_tenant(mock_queryset)

        # Assert
        mock_queryset.filter.assert_called_once_with(is_active=True)

    def test_shows_inactive_when_requested(self):
        """Test that inactive services are shown when show_inactive=true."""
        from smoothschedule.scheduling.schedule.views import ServiceViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/services/?show_inactive=true')
        request = Request(django_request)
        request.user = Mock()
        request.tenant = Mock()

        viewset = ServiceViewSet()
        viewset.request = request
        viewset.action = 'list'

        mock_queryset = Mock()

        # Act
        result = viewset.filter_queryset_for_tenant(mock_queryset)

        # Assert - filter should NOT be called when show_inactive=true
        mock_queryset.filter.assert_not_called()


class TestTimeBlockViewSetBlockedDates:
    """Test TimeBlockViewSet.blocked_dates action."""

    def test_blocked_dates_requires_date_parameters(self):
        """Test that blocked_dates requires start_date and end_date."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/time-blocks/blocked_dates/')
        request = Request(django_request)
        request.user = Mock()

        viewset = TimeBlockViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Mock get_queryset to avoid DB access
        with patch.object(viewset, 'get_queryset', return_value=Mock()):
            # Act
            response = viewset.blocked_dates(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'start_date and end_date are required' in response.data['error']

    def test_blocked_dates_validates_date_format(self):
        """Test that blocked_dates validates date format."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/time-blocks/blocked_dates/?start_date=invalid&end_date=invalid')
        request = Request(django_request)
        request.user = Mock()

        viewset = TimeBlockViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Mock get_queryset to avoid DB access
        with patch.object(viewset, 'get_queryset', return_value=Mock()):
            # Act
            response = viewset.blocked_dates(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'Invalid date format' in response.data['error']


class TestTimeBlockViewSetCheckConflicts:
    """Test TimeBlockViewSet.check_conflicts action."""

    def test_check_conflicts_validates_input(self):
        """Test that check_conflicts validates input data."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet
        from rest_framework.exceptions import ValidationError
        import pytest

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/check_conflicts/', {}, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {}
        request.user = Mock()

        viewset = TimeBlockViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Act & Assert - should raise validation error (missing required fields)
        # DRF viewsets raise ValidationError which is caught by DRF's exception handler
        # In unit tests without the full DRF stack, we expect the exception to be raised
        with pytest.raises(ValidationError):
            viewset.check_conflicts(request)


class TestTimeBlockViewSetPerformCreate:
    """Test TimeBlockViewSet.perform_create method."""

    def test_perform_create_auto_approves_for_privileged_users(self):
        """Test that perform_create auto-approves blocks for users with permission."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/', {})
        mock_user = Mock()
        mock_user.can_self_approve_time_off.return_value = True
        request.user = mock_user

        viewset = TimeBlockViewSet()
        viewset.request = request

        mock_serializer = Mock()

        # Act
        viewset.perform_create(mock_serializer)

        # Assert
        from smoothschedule.scheduling.schedule.models import TimeBlock
        mock_serializer.save.assert_called_once()
        call_kwargs = mock_serializer.save.call_args[1]
        assert call_kwargs['approval_status'] == TimeBlock.ApprovalStatus.APPROVED
        assert call_kwargs['created_by'] == mock_user

    def test_perform_create_sets_pending_for_staff(self):
        """Test that perform_create sets PENDING status for staff without permission."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/', {})
        mock_user = Mock()
        mock_user.can_self_approve_time_off.return_value = False
        request.user = mock_user

        viewset = TimeBlockViewSet()
        viewset.request = request

        mock_serializer = Mock()

        # Act
        viewset.perform_create(mock_serializer)

        # Assert
        from smoothschedule.scheduling.schedule.models import TimeBlock
        mock_serializer.save.assert_called_once()
        call_kwargs = mock_serializer.save.call_args[1]
        assert call_kwargs['approval_status'] == TimeBlock.ApprovalStatus.PENDING


class TestTimeBlockViewSetApproval:
    """Test TimeBlockViewSet.approve action."""

    def test_approve_requires_permission(self):
        """Test that approve checks user permission."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/1/approve/', {})
        mock_user = Mock()
        mock_user.can_review_time_off_requests.return_value = False
        request.user = mock_user

        viewset = TimeBlockViewSet()
        viewset.request = request

        mock_block = Mock()

        with patch.object(viewset, 'get_object', return_value=mock_block):
            response = viewset.approve(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'permission' in response.data['error'].lower()

    def test_approve_rejects_non_pending_blocks(self):
        """Test that approve rejects blocks not in PENDING status."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet
        from smoothschedule.scheduling.schedule.models import TimeBlock

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/1/approve/', {})
        mock_user = Mock()
        mock_user.can_review_time_off_requests.return_value = True
        request.user = mock_user

        viewset = TimeBlockViewSet()
        viewset.request = request

        mock_block = Mock()
        mock_block.approval_status = TimeBlock.ApprovalStatus.APPROVED
        mock_block.get_approval_status_display.return_value = 'Approved'

        with patch.object(viewset, 'get_object', return_value=mock_block):
            response = viewset.approve(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'already Approved' in response.data['error']


class TestTimeBlockViewSetDeny:
    """Test TimeBlockViewSet.deny action."""

    def test_deny_requires_permission(self):
        """Test that deny checks user permission."""
        from smoothschedule.scheduling.schedule.views import TimeBlockViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/1/deny/', {})
        mock_user = Mock()
        mock_user.can_review_time_off_requests.return_value = False
        request.user = mock_user

        viewset = TimeBlockViewSet()
        viewset.request = request

        mock_block = Mock()

        with patch.object(viewset, 'get_object', return_value=mock_block):
            response = viewset.deny(request, pk=1)

        # Assert
        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'permission' in response.data['error'].lower()


class TestHolidayViewSetDates:
    """Test HolidayViewSet.dates action."""

    def test_dates_validates_year_parameter(self):
        """Test that dates action validates year parameter."""
        from smoothschedule.scheduling.schedule.views import HolidayViewSet
        from rest_framework.request import Request

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/holidays/dates/?year=invalid')
        request = Request(django_request)
        request.user = Mock()

        viewset = HolidayViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Act
        with patch.object(viewset, 'get_queryset', return_value=[]):
            response = viewset.dates(request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'Invalid year' in response.data['error']

    def test_dates_uses_current_year_by_default(self):
        """Test that dates action uses current year when not specified."""
        from smoothschedule.scheduling.schedule.views import HolidayViewSet
        from rest_framework.request import Request
        from datetime import date

        # Arrange
        factory = APIRequestFactory()
        django_request = factory.get('/api/holidays/dates/')
        request = Request(django_request)
        request.user = Mock()

        viewset = HolidayViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        mock_holiday = Mock()
        mock_holiday.get_date_for_year.return_value = date(2025, 1, 1)
        mock_holiday.code = 'new_years'
        mock_holiday.name = 'New Years Day'

        mock_queryset = [mock_holiday]

        # Act
        with patch.object(viewset, 'get_queryset', return_value=mock_queryset):
            response = viewset.dates(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['year'] == date.today().year


class TestEmailTemplateViewSetPreview:
    """Test EmailTemplateViewSet.preview action."""

    def test_preview_renders_template_variables(self):
        """Test that preview renders template with variables."""
        from smoothschedule.scheduling.schedule.views import EmailTemplateViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/email-templates/preview/', {
            'subject': 'Hello {{CUSTOMER_NAME}}',
            'html_content': '<p>Your appointment is on {{APPOINTMENT_DATE}}</p>',
            'text_content': 'Your appointment is on {{APPOINTMENT_DATE}}'
        }, format='json')
        # Manually set data attribute to simulate DRF Request
        request.data = {
            'subject': 'Hello {{CUSTOMER_NAME}}',
            'html_content': '<p>Your appointment is on {{APPOINTMENT_DATE}}</p>',
            'text_content': 'Your appointment is on {{APPOINTMENT_DATE}}'
        }
        mock_user = Mock()
        mock_user.is_platform_user = False
        request.user = mock_user

        viewset = EmailTemplateViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        # Mock TemplateVariableParser - it's imported locally in the method
        # Define replacement function
        def replace_codes(template, context):
            result = template
            result = result.replace('{{CUSTOMER_NAME}}', 'John Doe')
            result = result.replace('{{APPOINTMENT_DATE}}', 'January 15, 2025')
            return result

        with patch('smoothschedule.scheduling.schedule.template_parser.TemplateVariableParser') as mock_parser_class:
            # Set replace_insertion_codes as a static/class method on the mock class
            mock_parser_class.replace_insertion_codes = replace_codes

            # Mock the connection to avoid subscription tier check (imported locally in function)
            with patch('django.db.connection') as mock_connection:
                # Make connection.tenant have a subscription_tier that's not FREE
                mock_tenant = Mock()
                mock_tenant.subscription_tier = 'PREMIUM'
                mock_connection.tenant = mock_tenant

                # Act
                response = viewset.preview(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert 'John Doe' in response.data['subject']
        assert 'January 15, 2025' in response.data['html_content']


class TestEmailTemplateViewSetDuplicate:
    """Test EmailTemplateViewSet.duplicate action."""

    def test_duplicate_creates_copy_with_modified_name(self):
        """Test that duplicate creates a copy with (Copy) appended."""
        from smoothschedule.scheduling.schedule.views import EmailTemplateViewSet
        from rest_framework.response import Response

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/email-templates/1/duplicate/', {}, format='json')
        mock_user = Mock(id=1)
        request.user = mock_user

        viewset = EmailTemplateViewSet()
        viewset.request = request
        viewset.format_kwarg = None

        mock_template = Mock()
        mock_template.name = 'Test Template'
        mock_template.description = 'Test Description'
        mock_template.subject = 'Test Subject'
        mock_template.html_content = '<p>Test</p>'
        mock_template.text_content = 'Test'
        mock_template.scope = 'BUSINESS'
        mock_template.category = 'APPOINTMENT'
        mock_template.preview_context = {}

        with patch.object(viewset, 'get_object', return_value=mock_template):
            with patch('smoothschedule.scheduling.schedule.views.EmailTemplate') as mock_model:
                from datetime import datetime

                # Create a proper mock with real datetime for created_at
                mock_new_template = Mock(
                    id=2,
                    name='Test Template (Copy)',
                    created_at=datetime(2025, 1, 1, 12, 0, 0),
                    created_by=None,
                    spec=['id', 'name', 'created_at', 'created_by', 'description', 'subject', 'html_content', 'text_content', 'scope', 'category']
                )
                mock_model.objects.create.return_value = mock_new_template

                # Mock the serializer to return a simple dict
                with patch.object(viewset, 'get_serializer') as mock_get_serializer:
                    # Create a mock serializer with .data as a plain dict
                    mock_serializer = Mock()
                    mock_serializer.data = {'id': 2, 'name': 'Test Template (Copy)'}
                    mock_get_serializer.return_value = mock_serializer

                    # Act
                    response = viewset.duplicate(request, pk=1)

        # Assert
        assert response.status_code == 201
        mock_model.objects.create.assert_called_once()
        create_kwargs = mock_model.objects.create.call_args[1]
        assert create_kwargs['name'] == 'Test Template (Copy)'


class TestEmailTemplateViewSetPerformCreate:
    """Test EmailTemplateViewSet.perform_create method."""

    def test_perform_create_sets_created_by(self):
        """Test that perform_create sets created_by from request user."""
        from smoothschedule.scheduling.schedule.views import EmailTemplateViewSet

        # Arrange
        factory = APIRequestFactory()
        request = factory.post('/api/email-templates/', {})
        mock_user = Mock(id=1)
        request.user = mock_user

        viewset = EmailTemplateViewSet()
        viewset.request = request

        mock_serializer = Mock()

        # Act
        viewset.perform_create(mock_serializer)

        # Assert
        mock_serializer.save.assert_called_once_with(created_by=mock_user)
