"""
Tests for Calendar Sync Feature Permission

Tests the can_use_calendar_sync permission checking throughout the calendar sync system.
Includes tests for:
- Permission denied when feature is disabled
- Permission granted when feature is enabled
- OAuth view permission checks
- Calendar sync view permission checks
"""

from django.test import TestCase
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from core.models import Tenant, OAuthCredential
from smoothschedule.users.models import User


class CalendarSyncPermissionTests(APITestCase):
    """
    Test suite for calendar sync feature permissions.

    Verifies that the can_use_calendar_sync permission is properly enforced
    across all calendar sync operations.
    """

    def setUp(self):
        """Set up test fixtures"""
        # Create a tenant without calendar sync enabled
        self.tenant = Tenant.objects.create(
            schema_name='test_tenant',
            name='Test Tenant',
            can_use_calendar_sync=False
        )

        # Create a user in this tenant
        self.user = User.objects.create_user(
            email='user@test.com',
            password='testpass123',
            tenant=self.tenant
        )

        # Initialize API client
        self.client = APIClient()

    def test_calendar_status_without_permission(self):
        """
        Test that users without can_use_calendar_sync cannot access calendar status.

        Expected: 403 Forbidden with upgrade message
        """
        self.client.force_authenticate(user=self.user)

        response = self.client.get('/api/calendar/status/')

        # Should be able to check status (it's informational)
        self.assertEqual(response.status_code, 200)
        self.assertFalse(response.data['can_use_calendar_sync'])
        self.assertEqual(response.data['total_connected'], 0)

    def test_calendar_list_without_permission(self):
        """
        Test that users without can_use_calendar_sync cannot list calendars.

        Expected: 403 Forbidden
        """
        self.client.force_authenticate(user=self.user)

        response = self.client.get('/api/calendar/list/')

        # Should return 403 Forbidden
        self.assertEqual(response.status_code, 403)
        self.assertIn('upgrade', response.data['error'].lower())

    def test_calendar_sync_without_permission(self):
        """
        Test that users without can_use_calendar_sync cannot sync calendars.

        Expected: 403 Forbidden
        """
        self.client.force_authenticate(user=self.user)

        response = self.client.post(
            '/api/calendar/sync/',
            {'credential_id': 1},
            format='json'
        )

        # Should return 403 Forbidden
        self.assertEqual(response.status_code, 403)
        self.assertIn('upgrade', response.data['error'].lower())

    def test_calendar_disconnect_without_permission(self):
        """
        Test that users without can_use_calendar_sync cannot disconnect calendars.

        Expected: 403 Forbidden
        """
        self.client.force_authenticate(user=self.user)

        response = self.client.delete(
            '/api/calendar/disconnect/',
            {'credential_id': 1},
            format='json'
        )

        # Should return 403 Forbidden
        self.assertEqual(response.status_code, 403)
        self.assertIn('upgrade', response.data['error'].lower())

    def test_oauth_calendar_initiate_without_permission(self):
        """
        Test that OAuth calendar initiation checks permission.

        Expected: 403 Forbidden when trying to initiate calendar OAuth
        """
        self.client.force_authenticate(user=self.user)

        response = self.client.post(
            '/api/oauth/google/initiate/',
            {'purpose': 'calendar'},
            format='json'
        )

        # Should return 403 Forbidden for calendar purpose
        self.assertEqual(response.status_code, 403)
        self.assertIn('Calendar Sync', response.data['error'])

    def test_oauth_email_initiate_without_permission(self):
        """
        Test that OAuth email initiation does NOT require calendar sync permission.

        Note: Email integration may have different permission checks,
        this test documents that calendar and email are separate.
        """
        self.client.force_authenticate(user=self.user)

        # Email purpose should be allowed without calendar sync permission
        # (assuming different permission for email)
        response = self.client.post(
            '/api/oauth/google/initiate/',
            {'purpose': 'email'},
            format='json'
        )

        # Should not be blocked by calendar sync permission
        # (Response may be 400 if OAuth not configured, but not 403 for this reason)
        self.assertNotEqual(response.status_code, 403)

    def test_calendar_list_with_permission(self):
        """
        Test that users WITH can_use_calendar_sync can list calendars.

        Expected: 200 OK with empty calendar list
        """
        # Enable calendar sync for tenant
        self.tenant.can_use_calendar_sync = True
        self.tenant.save()

        self.client.force_authenticate(user=self.user)

        response = self.client.get('/api/calendar/list/')

        # Should return 200 OK
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['success'])
        self.assertEqual(response.data['calendars'], [])

    def test_calendar_with_connected_credential(self):
        """
        Test calendar list with an actual OAuth credential.

        Expected: 200 OK with credential in the list
        """
        # Enable calendar sync
        self.tenant.can_use_calendar_sync = True
        self.tenant.save()

        # Create a calendar OAuth credential
        credential = OAuthCredential.objects.create(
            tenant=self.tenant,
            provider='google',
            purpose='calendar',
            email='user@gmail.com',
            access_token='fake_token_123',
            refresh_token='fake_refresh_123',
            is_valid=True,
            authorized_by=self.user,
        )

        self.client.force_authenticate(user=self.user)

        response = self.client.get('/api/calendar/list/')

        # Should return 200 OK with the credential
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['success'])
        self.assertEqual(len(response.data['calendars']), 1)

        calendar = response.data['calendars'][0]
        self.assertEqual(calendar['email'], 'user@gmail.com')
        self.assertEqual(calendar['provider'], 'Google')
        self.assertTrue(calendar['is_valid'])

    def test_calendar_status_with_permission(self):
        """
        Test calendar status check when permission is granted.

        Expected: 200 OK with feature enabled
        """
        # Enable calendar sync
        self.tenant.can_use_calendar_sync = True
        self.tenant.save()

        self.client.force_authenticate(user=self.user)

        response = self.client.get('/api/calendar/status/')

        # Should return 200 OK with feature enabled
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['success'])
        self.assertTrue(response.data['can_use_calendar_sync'])
        self.assertTrue(response.data['feature_enabled'])

    def test_unauthenticated_calendar_access(self):
        """
        Test that unauthenticated users cannot access calendar endpoints.

        Expected: 401 Unauthorized
        """
        # Don't authenticate

        response = self.client.get('/api/calendar/list/')

        # Should return 401 Unauthorized
        self.assertEqual(response.status_code, 401)

    def test_tenant_has_feature_method(self):
        """
        Test the Tenant.has_feature() method for calendar sync.

        Expected: Method returns correct boolean based on field
        """
        # Initially disabled
        self.assertFalse(self.tenant.has_feature('can_use_calendar_sync'))

        # Enable it
        self.tenant.can_use_calendar_sync = True
        self.tenant.save()

        # Check again
        self.assertTrue(self.tenant.has_feature('can_use_calendar_sync'))


class CalendarSyncIntegrationTests(APITestCase):
    """
    Integration tests for calendar sync with permission checks.

    Tests realistic workflows of connecting and syncing calendars.
    """

    def setUp(self):
        """Set up test fixtures"""
        # Create a tenant WITH calendar sync enabled
        self.tenant = Tenant.objects.create(
            schema_name='pro_tenant',
            name='Professional Tenant',
            can_use_calendar_sync=True  # Premium feature enabled
        )

        # Create a user
        self.user = User.objects.create_user(
            email='pro@example.com',
            password='testpass123',
            tenant=self.tenant
        )

        self.client = APIClient()
        self.client.force_authenticate(user=self.user)

    def test_full_calendar_workflow(self):
        """
        Test complete workflow: Check status -> List -> Add -> Sync -> Remove

        Expected: All steps succeed with permission checks passing
        """
        # Step 1: Check status
        response = self.client.get('/api/calendar/status/')
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['can_use_calendar_sync'])

        # Step 2: List calendars (empty initially)
        response = self.client.get('/api/calendar/list/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data['calendars']), 0)

        # Step 3: Create credential (simulating OAuth completion)
        credential = OAuthCredential.objects.create(
            tenant=self.tenant,
            provider='google',
            purpose='calendar',
            email='calendar@gmail.com',
            access_token='token_123',
            is_valid=True,
            authorized_by=self.user,
        )

        # Step 4: List again (should see the credential)
        response = self.client.get('/api/calendar/list/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data['calendars']), 1)

        # Step 5: Sync from the calendar
        response = self.client.post(
            '/api/calendar/sync/',
            {
                'credential_id': credential.id,
                'calendar_id': 'primary',
                'start_date': '2025-01-01',
                'end_date': '2025-12-31',
            },
            format='json'
        )
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['success'])

        # Step 6: Disconnect the calendar
        response = self.client.delete(
            '/api/calendar/disconnect/',
            {'credential_id': credential.id},
            format='json'
        )
        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.data['success'])

        # Step 7: Verify it's deleted
        response = self.client.get('/api/calendar/list/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data['calendars']), 0)


class TenantPermissionModelTests(TestCase):
    """
    Unit tests for the Tenant model's calendar sync permission field.
    """

    def test_tenant_can_use_calendar_sync_default(self):
        """Test that can_use_calendar_sync defaults to False"""
        tenant = Tenant.objects.create(
            schema_name='test',
            name='Test'
        )

        self.assertFalse(tenant.can_use_calendar_sync)

    def test_tenant_can_use_calendar_sync_enable(self):
        """Test enabling calendar sync on a tenant"""
        tenant = Tenant.objects.create(
            schema_name='test',
            name='Test',
            can_use_calendar_sync=False
        )

        tenant.can_use_calendar_sync = True
        tenant.save()

        refreshed = Tenant.objects.get(pk=tenant.pk)
        self.assertTrue(refreshed.can_use_calendar_sync)

    def test_has_feature_with_other_permissions(self):
        """Test that has_feature correctly checks other permissions too"""
        tenant = Tenant.objects.create(
            schema_name='test',
            name='Test',
            can_use_calendar_sync=True,
            can_use_webhooks=False,
        )

        self.assertTrue(tenant.has_feature('can_use_calendar_sync'))
        self.assertFalse(tenant.has_feature('can_use_webhooks'))
