"""
Unit tests for identity/core API views (quota management).

Tests the function-based views for quota status, resources, archiving, and unarchiving.
Uses mocks to avoid database access and simulate the request/response cycle.
"""
from unittest.mock import Mock, patch, MagicMock
from rest_framework.test import APIRequestFactory
from rest_framework import status
import pytest


class TestIsOwnerOrManagerHelper:
    """Test is_owner_or_manager helper function."""

    def test_function_exists(self):
        """Test helper function is defined."""
        from smoothschedule.identity.core.api_views import is_owner_or_manager

        assert callable(is_owner_or_manager)

    def test_returns_true_for_owner(self):
        """Should return True for tenant owner."""
        from smoothschedule.identity.core.api_views import is_owner_or_manager
        from smoothschedule.identity.users.models import User

        mock_user = Mock()
        mock_user.role = User.Role.TENANT_OWNER

        result = is_owner_or_manager(mock_user)

        assert result is True

    def test_returns_true_for_manager(self):
        """Should return True for tenant manager."""
        from smoothschedule.identity.core.api_views import is_owner_or_manager
        from smoothschedule.identity.users.models import User

        mock_user = Mock()
        mock_user.role = User.Role.TENANT_MANAGER

        result = is_owner_or_manager(mock_user)

        assert result is True

    def test_returns_false_for_staff(self):
        """Should return False for staff role."""
        from smoothschedule.identity.core.api_views import is_owner_or_manager
        from smoothschedule.identity.users.models import User

        mock_user = Mock()
        mock_user.role = User.Role.TENANT_STAFF

        result = is_owner_or_manager(mock_user)

        assert result is False

    def test_returns_false_for_customer(self):
        """Should return False for customer role."""
        from smoothschedule.identity.core.api_views import is_owner_or_manager
        from smoothschedule.identity.users.models import User

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER

        result = is_owner_or_manager(mock_user)

        assert result is False


class TestQuotaStatusView:
    """Test quota_status_view function."""

    def test_view_exists(self):
        """Test view function is defined."""
        from smoothschedule.identity.core.api_views import quota_status_view

        assert callable(quota_status_view)

    @patch('smoothschedule.identity.core.api_views.QuotaService')
    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_tenant(self, mock_is_owner, mock_service):
        """Should return 400 when user has no tenant."""
        from smoothschedule.identity.core.api_views import quota_status_view

        factory = APIRequestFactory()
        request = factory.get('/api/quota/status/')
        request.user = Mock(tenant=None)

        response = quota_status_view(request)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant associated' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.QuotaService')
    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_403_for_non_owner_manager(self, mock_is_owner, mock_service):
        """Should return 403 when user is not owner or manager."""
        from smoothschedule.identity.core.api_views import quota_status_view

        mock_is_owner.return_value = False

        factory = APIRequestFactory()
        request = factory.get('/api/quota/status/')
        request.user = Mock(tenant=Mock())

        response = quota_status_view(request)

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'Only owners and managers' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.QuotaService')
    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_quota_status_for_owner(self, mock_is_owner, mock_service_class):
        """Should return quota status for owner."""
        from smoothschedule.identity.core.api_views import quota_status_view

        mock_is_owner.return_value = True

        mock_service = Mock()
        mock_service.get_active_overages.return_value = []
        mock_service.QUOTA_CONFIG = {
            'MAX_RESOURCES': {'display_name': 'Resources'},
        }
        mock_service.get_current_usage.return_value = 5
        mock_service.get_limit.return_value = 10
        mock_service_class.return_value = mock_service

        factory = APIRequestFactory()
        request = factory.get('/api/quota/status/')
        request.user = Mock(tenant=Mock())

        response = quota_status_view(request)

        assert response.status_code == status.HTTP_200_OK
        assert 'active_overages' in response.data
        assert 'usage' in response.data


class TestQuotaResourcesView:
    """Test quota_resources_view function."""

    def test_view_exists(self):
        """Test view function is defined."""
        from smoothschedule.identity.core.api_views import quota_resources_view

        assert callable(quota_resources_view)

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_tenant(self, mock_is_owner):
        """Should return 400 when user has no tenant."""
        from smoothschedule.identity.core.api_views import quota_resources_view

        factory = APIRequestFactory()
        request = factory.get('/api/quota/resources/MAX_RESOURCES/')
        request.user = Mock(tenant=None)

        response = quota_resources_view(request, quota_type='MAX_RESOURCES')

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant associated' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_403_for_non_owner_manager(self, mock_is_owner):
        """Should return 403 when user is not owner or manager."""
        from smoothschedule.identity.core.api_views import quota_resources_view

        mock_is_owner.return_value = False

        factory = APIRequestFactory()
        request = factory.get('/api/quota/resources/MAX_RESOURCES/')
        request.user = Mock(tenant=Mock())

        response = quota_resources_view(request, quota_type='MAX_RESOURCES')

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'Only owners and managers' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_for_unknown_quota_type(self, mock_is_owner):
        """Should return 400 for unknown quota type."""
        from smoothschedule.identity.core.api_views import quota_resources_view

        mock_is_owner.return_value = True

        factory = APIRequestFactory()
        request = factory.get('/api/quota/resources/UNKNOWN_TYPE/')
        request.user = Mock(tenant=Mock())

        response = quota_resources_view(request, quota_type='UNKNOWN_TYPE')

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'Unknown quota type' in response.data['error']


class TestQuotaArchiveView:
    """Test quota_archive_view function."""

    def test_view_exists(self):
        """Test view function is defined."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        assert callable(quota_archive_view)

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_tenant(self, mock_is_owner):
        """Should return 400 when user has no tenant."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        factory = APIRequestFactory()
        request = factory.post('/api/quota/archive/', {}, format='json')
        request.user = Mock(tenant=None)
        # Mock the data attribute
        request.data = {'quota_type': 'MAX_RESOURCES', 'resource_ids': [1]}

        response = quota_archive_view(request)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant associated' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_403_for_non_owner_manager(self, mock_is_owner):
        """Should return 403 when user is not owner or manager."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        mock_is_owner.return_value = False

        factory = APIRequestFactory()
        request = factory.post('/api/quota/archive/', {}, format='json')
        request.user = Mock(tenant=Mock())
        request.data = {'quota_type': 'MAX_RESOURCES', 'resource_ids': [1]}

        response = quota_archive_view(request)

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'Only owners and managers' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_quota_type(self, mock_is_owner):
        """Should return 400 when quota_type is missing."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        mock_is_owner.return_value = True

        factory = APIRequestFactory()
        request = factory.post('/api/quota/archive/', {}, format='json')
        request.user = Mock(tenant=Mock())
        request.data = {'resource_ids': [1]}

        response = quota_archive_view(request)

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

    def test_view_requires_authentication(self):
        """View should require authentication (IsAuthenticated)."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        # Verify the view exists and has the decorator applied
        assert callable(quota_archive_view)
        # DRF decorated functions have these attributes
        assert hasattr(quota_archive_view, 'cls')

    def test_validates_request_data(self):
        """View validates quota_type and resource_ids."""
        from smoothschedule.identity.core.api_views import quota_archive_view

        # Function exists and can be inspected
        assert callable(quota_archive_view)


class TestQuotaUnarchiveView:
    """Test quota_unarchive_view function."""

    def test_view_exists(self):
        """Test view function is defined."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        assert callable(quota_unarchive_view)

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_tenant(self, mock_is_owner):
        """Should return 400 when user has no tenant."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        factory = APIRequestFactory()
        request = factory.post('/api/quota/unarchive/', {}, format='json')
        request.user = Mock(tenant=None)
        request.data = {'quota_type': 'MAX_RESOURCES', 'resource_id': 1}

        response = quota_unarchive_view(request)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant associated' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_403_for_non_owner_manager(self, mock_is_owner):
        """Should return 403 when user is not owner or manager."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        mock_is_owner.return_value = False

        factory = APIRequestFactory()
        request = factory.post('/api/quota/unarchive/', {}, format='json')
        request.user = Mock(tenant=Mock())
        request.data = {'quota_type': 'MAX_RESOURCES', 'resource_id': 1}

        response = quota_unarchive_view(request)

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'Only owners and managers' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_missing_params(self, mock_is_owner):
        """Should return 400 when required params are missing."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        mock_is_owner.return_value = True

        factory = APIRequestFactory()
        request = factory.post('/api/quota/unarchive/', {}, format='json')
        request.user = Mock(tenant=Mock())
        request.data = {}

        response = quota_unarchive_view(request)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'quota_type and resource_id are required' in response.data['error']

    def test_view_requires_authentication(self):
        """View should require authentication (IsAuthenticated)."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        # Verify the view exists and has the decorator applied
        assert callable(quota_unarchive_view)
        # DRF decorated functions have these attributes
        assert hasattr(quota_unarchive_view, 'cls')

    def test_validates_request_data(self):
        """View validates quota_type and resource_id."""
        from smoothschedule.identity.core.api_views import quota_unarchive_view

        # Function exists and can be inspected
        assert callable(quota_unarchive_view)


class TestQuotaOverageDetailView:
    """Test quota_overage_detail_view function."""

    def test_view_exists(self):
        """Test view function is defined."""
        from smoothschedule.identity.core.api_views import quota_overage_detail_view

        assert callable(quota_overage_detail_view)

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_400_when_no_tenant(self, mock_is_owner):
        """Should return 400 when user has no tenant."""
        from smoothschedule.identity.core.api_views import quota_overage_detail_view

        factory = APIRequestFactory()
        request = factory.get('/api/quota/overages/1/')
        request.user = Mock(tenant=None)

        response = quota_overage_detail_view(request, overage_id=1)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'No tenant associated' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_403_for_non_owner_manager(self, mock_is_owner):
        """Should return 403 when user is not owner or manager."""
        from smoothschedule.identity.core.api_views import quota_overage_detail_view

        mock_is_owner.return_value = False

        factory = APIRequestFactory()
        request = factory.get('/api/quota/overages/1/')
        request.user = Mock(tenant=Mock())

        response = quota_overage_detail_view(request, overage_id=1)

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'Only owners and managers' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.QuotaOverage')
    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_404_when_overage_not_found(self, mock_is_owner, mock_overage_model):
        """Should return 404 when overage doesn't exist."""
        from smoothschedule.identity.core.api_views import quota_overage_detail_view

        mock_is_owner.return_value = True
        mock_overage_model.DoesNotExist = Exception
        mock_overage_model.objects.get.side_effect = mock_overage_model.DoesNotExist

        factory = APIRequestFactory()
        request = factory.get('/api/quota/overages/999/')
        request.user = Mock(tenant=Mock())

        response = quota_overage_detail_view(request, overage_id=999)

        assert response.status_code == status.HTTP_404_NOT_FOUND
        assert 'Overage not found' in response.data['error']

    @patch('smoothschedule.identity.core.api_views.QuotaService')
    @patch('smoothschedule.identity.core.api_views.QuotaOverage')
    @patch('smoothschedule.identity.core.api_views.is_owner_or_manager')
    def test_returns_overage_details(self, mock_is_owner, mock_overage_model, mock_service_class):
        """Should return overage details."""
        from smoothschedule.identity.core.api_views import quota_overage_detail_view
        from datetime import datetime

        mock_is_owner.return_value = True

        # Mock the overage object
        mock_overage = Mock()
        mock_overage.id = 1
        mock_overage.quota_type = 'MAX_RESOURCES'
        mock_overage.status = 'ACTIVE'
        mock_overage.current_usage = 15
        mock_overage.allowed_limit = 10
        mock_overage.overage_amount = 5
        mock_overage.days_remaining = 10
        mock_overage.grace_period_ends_at = datetime(2024, 1, 15)
        mock_overage.created_at = datetime(2024, 1, 1)
        mock_overage.initial_email_sent_at = None
        mock_overage.week_reminder_sent_at = None
        mock_overage.day_reminder_sent_at = None
        mock_overage.archived_resource_ids = []

        mock_overage_model.objects.get.return_value = mock_overage
        mock_overage_model.DoesNotExist = Exception

        # Mock quota service
        mock_service = Mock()
        mock_service.QUOTA_CONFIG = {
            'MAX_RESOURCES': {'display_name': 'Resources'}
        }
        mock_service_class.return_value = mock_service

        factory = APIRequestFactory()
        request = factory.get('/api/quota/overages/1/')
        mock_tenant = Mock()
        request.user = Mock(tenant=mock_tenant)

        response = quota_overage_detail_view(request, overage_id=1)

        assert response.status_code == status.HTTP_200_OK
        assert response.data['id'] == 1
        assert response.data['quota_type'] == 'MAX_RESOURCES'
        assert response.data['display_name'] == 'Resources'
        assert response.data['current_usage'] == 15
        assert response.data['allowed_limit'] == 10
        assert response.data['overage_amount'] == 5
