"""
Unit tests for Location-related serializer validation.

Tests LocationRequiredMixin behavior on Event, Resource, and TimeBlock serializers.
DO NOT use @pytest.mark.django_db for unit tests - use mocks.
"""
from unittest.mock import Mock, patch, MagicMock
from rest_framework.test import APIRequestFactory
import pytest


class TestEventSerializerLocationValidation:
    """Test EventSerializer location validation with LocationRequiredMixin."""

    def test_location_required_when_multi_location_enabled(self):
        """Test location is required on create when multi-location active."""
        from smoothschedule.scheduling.schedule.serializers import EventSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/events/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = EventSerializer(
                data={
                    'title': 'Test Event',
                    'start_time': '2025-01-15T10:00:00Z',
                    'end_time': '2025-01-15T11:00:00Z',
                    # location is missing
                },
                context={'request': request}
            )

            assert not serializer.is_valid()
            assert 'location' in serializer.errors

    def test_location_not_required_when_single_location(self):
        """Test location is NOT required when only one location exists."""
        from smoothschedule.scheduling.schedule.serializers import EventSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/events/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        with patch.object(LocationService, 'requires_location_on_entities', return_value=False):
            serializer = EventSerializer(
                data={
                    'title': 'Test Event',
                    'start_time': '2025-01-15T10:00:00Z',
                    'end_time': '2025-01-15T11:00:00Z',
                    # location is missing but should be OK
                },
                context={'request': request}
            )

            # Should be valid (or only have non-location errors)
            is_valid = serializer.is_valid()
            if not is_valid:
                assert 'location' not in serializer.errors

    def test_update_preserves_existing_location(self):
        """Test PATCH preserves existing location without error."""
        from smoothschedule.scheduling.schedule.serializers import EventSerializer
        from smoothschedule.scheduling.schedule.services import LocationService
        from datetime import datetime, timedelta
        from django.utils import timezone

        factory = APIRequestFactory()
        request = factory.patch('/api/events/1/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        # Mock existing event with location and valid times
        mock_event = Mock()
        mock_event.location = Mock(pk=1)
        mock_event.location_id = 1
        # Provide valid times for the event validation
        mock_event.start_time = timezone.now() + timedelta(hours=1)
        mock_event.end_time = timezone.now() + timedelta(hours=2)
        mock_event.id = 1

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = EventSerializer(
                instance=mock_event,
                data={'title': 'Updated Title'},
                partial=True,
                context={'request': request}
            )

            # Should not raise location error since instance has location
            is_valid = serializer.is_valid()
            if not is_valid:
                assert 'location' not in serializer.errors


class TestResourceSerializerLocationValidation:
    """Test ResourceSerializer location validation with LocationRequiredMixin."""

    def test_location_required_for_non_mobile_when_multi_location(self):
        """Test non-mobile resources require location when multi-location active."""
        from smoothschedule.scheduling.schedule.serializers import ResourceSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/resources/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = ResourceSerializer(
                data={
                    'name': 'Test Resource',
                    'is_mobile': False,
                    # location is missing
                },
                context={'request': request}
            )

            assert not serializer.is_valid()
            assert 'location' in serializer.errors

    def test_location_not_required_for_mobile_resource(self):
        """Test mobile resources do NOT require location."""
        from smoothschedule.scheduling.schedule.serializers import ResourceSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/resources/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = ResourceSerializer(
                data={
                    'name': 'Mobile Plumber',
                    'is_mobile': True,
                    # location is missing but OK for mobile
                },
                context={'request': request}
            )

            is_valid = serializer.is_valid()
            if not is_valid:
                # Should not have location error
                assert 'location' not in serializer.errors

    def test_location_not_required_when_single_location(self):
        """Test location not required when only one location exists."""
        from smoothschedule.scheduling.schedule.serializers import ResourceSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/resources/')
        mock_tenant = Mock()
        request.tenant = mock_tenant

        with patch.object(LocationService, 'requires_location_on_entities', return_value=False):
            serializer = ResourceSerializer(
                data={
                    'name': 'Test Resource',
                    'is_mobile': False,
                },
                context={'request': request}
            )

            is_valid = serializer.is_valid()
            if not is_valid:
                assert 'location' not in serializer.errors


class TestTimeBlockSerializerLocationValidation:
    """Test TimeBlockSerializer location validation with LocationRequiredMixin."""

    def test_business_wide_skips_location_validation(self):
        """Test is_business_wide=True skips location validation."""
        from smoothschedule.scheduling.schedule.serializers import TimeBlockSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/')
        mock_tenant = Mock()
        request.tenant = mock_tenant
        # Mock authenticated user for staff permission checks
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = TimeBlockSerializer(
                data={
                    'title': 'Holiday Closure',
                    'block_type': 'HARD',
                    'is_business_wide': True,
                    'start_date': '2025-01-01',
                    'end_date': '2025-01-01',
                    'all_day': True,
                    'recurrence_type': 'NONE',
                    # Should not require location for business-wide
                },
                context={'request': request}
            )

            is_valid = serializer.is_valid()
            if not is_valid:
                # Should not have location error for business-wide blocks
                assert 'location' not in serializer.errors

    def test_location_level_block_requires_location_when_multi(self):
        """Test location-level blocks (no resource) require location when multi-location."""
        from smoothschedule.scheduling.schedule.serializers import TimeBlockSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/')
        mock_tenant = Mock()
        request.tenant = mock_tenant
        # Mock authenticated owner (not staff) to avoid staff permission issues
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = TimeBlockSerializer(
                data={
                    'title': 'Location Renovation',
                    'block_type': 'HARD',
                    'is_business_wide': False,
                    'start_date': '2025-01-15',
                    'end_date': '2025-01-20',
                    'all_day': True,
                    'recurrence_type': 'NONE',
                    # resource is null (location-level block)
                    # location is missing - should fail
                },
                context={'request': request}
            )

            assert not serializer.is_valid()
            assert 'location' in serializer.errors

    def test_resource_specific_block_allowed_without_location(self):
        """Test resource-specific blocks don't require location (direct validation test)."""
        from smoothschedule.scheduling.schedule.serializers import TimeBlockSerializer
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/time-blocks/')
        mock_tenant = Mock()
        request.tenant = mock_tenant
        request.user = Mock(is_authenticated=True, role='TENANT_OWNER')

        # Create a mock instance to simulate update scenario
        mock_block = Mock()
        mock_block.is_business_wide = False
        mock_block.resource = Mock(pk=1)  # Resource is set
        mock_block.location = None
        mock_block.recurrence_type = 'NONE'
        mock_block.start_date = '2025-01-15'

        with patch.object(LocationService, 'requires_location_on_entities', return_value=True):
            serializer = TimeBlockSerializer(
                instance=mock_block,
                data={
                    'title': 'Updated Title',
                },
                partial=True,
                context={'request': request}
            )

            is_valid = serializer.is_valid()
            if not is_valid:
                # Should not have location error for resource-specific blocks
                assert 'location' not in serializer.errors
