"""
Unit tests for LocationViewSet.

Tests viewset methods and actions with mocks to avoid database access.
DO NOT use @pytest.mark.django_db for unit tests - use mocks.
"""
from unittest.mock import Mock, patch, MagicMock, PropertyMock
from rest_framework.test import APIRequestFactory
from rest_framework import status
import pytest


class TestLocationViewSetGetQueryset:
    """Test LocationViewSet.get_queryset method."""

    def test_returns_empty_when_no_tenant(self):
        """Test get_queryset returns empty when no tenant context."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet

        factory = APIRequestFactory()
        request = factory.get('/api/locations/')
        request.user = Mock(is_authenticated=True)
        request.tenant = None

        viewset = LocationViewSet()
        viewset.request = request
        viewset.format_kwarg = None
        viewset.kwargs = {}

        with patch.object(LocationViewSet, 'get_queryset') as mock_qs:
            mock_qs.return_value.none.return_value = []
            # The actual implementation filters by tenant
            # When no tenant, should return empty


class TestLocationViewSetPerformCreate:
    """Test LocationViewSet.perform_create method."""

    def test_first_location_becomes_primary(self):
        """Test that first location for tenant is automatically primary."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.models import Location

        factory = APIRequestFactory()
        request = factory.post('/api/locations/')
        request.user = Mock(is_authenticated=True)
        mock_tenant = Mock()
        request.tenant = mock_tenant

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

        mock_serializer = Mock()

        # Mock that no locations exist yet
        with patch.object(Location.objects, 'filter') as mock_filter:
            mock_filter.return_value.exists.return_value = False

            viewset.perform_create(mock_serializer)

            # Should save with is_primary=True for first location
            mock_serializer.save.assert_called_once()
            call_kwargs = mock_serializer.save.call_args[1]
            assert call_kwargs['business'] == mock_tenant
            assert call_kwargs['is_primary'] is True
            assert call_kwargs['is_active'] is True

    def test_subsequent_location_not_primary(self):
        """Test that subsequent locations are not automatically primary."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.models import Location

        factory = APIRequestFactory()
        request = factory.post('/api/locations/')
        request.user = Mock(is_authenticated=True)
        mock_tenant = Mock()
        request.tenant = mock_tenant

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

        mock_serializer = Mock()

        # Mock that locations already exist
        with patch.object(Location.objects, 'filter') as mock_filter:
            mock_filter.return_value.exists.return_value = True

            viewset.perform_create(mock_serializer)

            # Should save with is_primary=False for subsequent locations
            mock_serializer.save.assert_called_once()
            call_kwargs = mock_serializer.save.call_args[1]
            assert call_kwargs['is_primary'] is False


class TestLocationViewSetSetPrimaryAction:
    """Test LocationViewSet.set_primary action."""

    def test_set_primary_calls_service(self):
        """Test set_primary action delegates to LocationService."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/locations/1/set_primary/')
        request.user = Mock(is_authenticated=True)

        mock_location = Mock()
        mock_location.pk = 1
        mock_location.business = Mock()

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

        with patch.object(viewset, 'get_object', return_value=mock_location), \
             patch.object(LocationService, 'set_primary') as mock_set_primary, \
             patch('smoothschedule.scheduling.schedule.views.LocationSerializer') as mock_serializer:

            mock_set_primary.return_value = mock_location
            mock_serializer.return_value.data = {'id': 1, 'name': 'Test'}

            response = viewset.set_primary(request)

            mock_set_primary.assert_called_once_with(mock_location.business, mock_location.pk)
            assert response.status_code == status.HTTP_200_OK


class TestLocationViewSetSetActiveAction:
    """Test LocationViewSet.set_active action."""

    def test_set_active_requires_is_active_field(self):
        """Test set_active action requires is_active in request body."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet

        factory = APIRequestFactory()
        request = factory.post('/api/locations/1/set_active/', {}, format='json')
        request.user = Mock(is_authenticated=True)
        request.data = {}  # Missing is_active

        mock_location = Mock()
        mock_location.pk = 1

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

        with patch.object(viewset, 'get_object', return_value=mock_location):
            response = viewset.set_active(request)

            assert response.status_code == status.HTTP_400_BAD_REQUEST
            assert 'is_active' in response.data['detail']

    def test_deactivate_blocked_when_last_active(self):
        """Test cannot deactivate last active location."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/locations/1/set_active/', {'is_active': False}, format='json')
        request.user = Mock(is_authenticated=True)
        request.data = {'is_active': False}

        mock_location = Mock()
        mock_location.pk = 1
        mock_location.is_active = True
        mock_location.business = Mock()

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

        with patch.object(viewset, 'get_object', return_value=mock_location), \
             patch.object(LocationService, 'validate_at_least_one_active') as mock_validate:

            mock_validate.return_value = (False, "Cannot deactivate the last active location.")

            response = viewset.set_active(request)

            assert response.status_code == status.HTTP_400_BAD_REQUEST
            assert 'last active' in response.data['detail'].lower()

    def test_reactivate_blocked_when_at_quota(self):
        """Test cannot reactivate when at quota limit."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.post('/api/locations/1/set_active/', {'is_active': True}, format='json')
        request.user = Mock(is_authenticated=True)
        request.data = {'is_active': True}

        mock_location = Mock()
        mock_location.pk = 1
        mock_location.is_active = False  # Currently inactive
        mock_location.business = Mock()

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

        with patch.object(viewset, 'get_object', return_value=mock_location), \
             patch.object(LocationService, 'can_add_location') as mock_can_add:

            mock_can_add.return_value = (False, "Location quota reached (3).")

            response = viewset.set_active(request)

            assert response.status_code == status.HTTP_400_BAD_REQUEST
            assert 'quota' in response.data['detail'].lower()


class TestLocationViewSetPerformDestroy:
    """Test LocationViewSet.perform_destroy method."""

    def test_destroy_blocked_when_last_active(self):
        """Test cannot delete last active location."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.services import LocationService
        from rest_framework.exceptions import ValidationError

        factory = APIRequestFactory()
        request = factory.delete('/api/locations/1/')
        request.user = Mock(is_authenticated=True)

        mock_location = Mock()
        mock_location.pk = 1
        mock_location.is_primary = False
        mock_location.business = Mock()

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

        with patch.object(LocationService, 'validate_at_least_one_active') as mock_validate:
            mock_validate.return_value = (False, "Cannot delete the last active location.")

            with pytest.raises(ValidationError) as exc_info:
                viewset.perform_destroy(mock_location)

            assert 'last active' in str(exc_info.value.detail).lower()

    def test_destroy_promotes_next_when_deleting_primary(self):
        """Test deleting primary promotes next location."""
        from smoothschedule.scheduling.schedule.views import LocationViewSet
        from smoothschedule.scheduling.schedule.services import LocationService

        factory = APIRequestFactory()
        request = factory.delete('/api/locations/1/')
        request.user = Mock(is_authenticated=True)

        mock_location = Mock()
        mock_location.pk = 1
        mock_location.is_primary = True
        mock_location.business = Mock()

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

        with patch.object(LocationService, 'validate_at_least_one_active') as mock_validate, \
             patch.object(LocationService, 'promote_next_primary') as mock_promote:

            mock_validate.return_value = (True, None)

            viewset.perform_destroy(mock_location)

            mock_promote.assert_called_once_with(mock_location.business, mock_location.pk)
            mock_location.delete.assert_called_once()


class TestLocationSerializerValidation:
    """Test LocationSerializer validation."""

    def test_serializer_includes_required_fields(self):
        """Test LocationSerializer has all required fields."""
        from smoothschedule.scheduling.schedule.serializers import LocationSerializer

        serializer = LocationSerializer()
        fields = serializer.fields.keys()

        # Check key fields exist
        assert 'id' in fields
        assert 'name' in fields
        assert 'is_active' in fields
        assert 'is_primary' in fields
        assert 'display_order' in fields

    def test_is_primary_is_readonly(self):
        """Test is_primary field is read-only."""
        from smoothschedule.scheduling.schedule.serializers import LocationSerializer

        serializer = LocationSerializer()
        assert serializer.fields['is_primary'].read_only is True
