"""
Tests for the UserActivity to Activity migration.
"""
from django.test import TestCase, TransactionTestCase
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.contrib.contenttypes.models import ContentType

from apps.activities.models import Activity, ActivityCategory
from apps.activities.helpers import log_user_activity, get_user_activities

User = get_user_model()


class ActivityMigrationTest(TransactionTestCase):
    """
    Test the migration from UserActivity to Activity model.
    """
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            email='test@example.com',
            username='testuser',
            password='testpass123'
        )
        
        # Create some test categories
        self.auth_category = ActivityCategory.objects.create(
            name='Authentication',
            code='authentication',
            description='User authentication activities',
            color='#28a745',
            icon='fas fa-sign-in-alt',
            is_system=True
        )
        
        self.general_category = ActivityCategory.objects.create(
            name='General',
            code='general',
            description='General system activities',
            color='#6c757d',
            icon='fas fa-cog',
            is_system=True
        )
    
    def test_log_user_activity_helper(self):
        """Test the log_user_activity helper function."""
        # Test login activity
        activity = log_user_activity(
            user=self.user,
            action='login',
            object_type='User',
            object_id=self.user.id,
            object_repr=str(self.user),
            details={'method': 'email'},
            ip_address='127.0.0.1',
            user_agent='Test Browser'
        )
        
        self.assertIsInstance(activity, Activity)
        self.assertEqual(activity.user, self.user)
        self.assertEqual(activity.action, 'LOGIN')
        self.assertEqual(activity.ip_address, '127.0.0.1')
        self.assertEqual(activity.user_agent, 'Test Browser')
        self.assertEqual(activity.metadata, {'method': 'email'})
        self.assertTrue(activity.is_successful)
        
        # Test that category was set correctly
        self.assertEqual(activity.category.code, 'authentication')
    
    def test_get_user_activities_helper(self):
        """Test the get_user_activities helper function."""
        # Create some activities
        log_user_activity(
            user=self.user,
            action='login',
            details={'method': 'email'}
        )
        
        log_user_activity(
            user=self.user,
            action='profile_update',
            details={'field': 'name'}
        )
        
        # Test getting all activities
        activities = get_user_activities(self.user)
        self.assertEqual(len(activities), 2)
        
        # Test getting limited activities
        activities = get_user_activities(self.user, limit=1)
        self.assertEqual(len(activities), 1)
        
        # Test ordering (should be newest first)
        activities = list(get_user_activities(self.user))
        self.assertEqual(activities[0].action, 'UPDATE')  # profile_update maps to UPDATE
        self.assertEqual(activities[1].action, 'LOGIN')
    
    def test_action_mapping(self):
        """Test that old actions are mapped to new actions correctly."""
        test_cases = [
            ('login', 'LOGIN'),
            ('logout', 'LOGOUT'),
            ('password_change', 'PASSWORD_CHANGE'),
            ('password_reset', 'PASSWORD_RESET'),
            ('account_verified', 'ACCOUNT_VERIFIED'),
            ('profile_update', 'UPDATE'),
            ('create', 'CREATE'),
            ('read', 'READ'),
            ('update', 'UPDATE'),
            ('delete', 'DELETE'),
            ('export', 'EXPORT'),
            ('import', 'IMPORT'),
            ('admin', 'ADMIN'),
        ]
        
        for old_action, expected_new_action in test_cases:
            activity = log_user_activity(
                user=self.user,
                action=old_action,
                details={'test': True}
            )
            self.assertEqual(activity.action, expected_new_action)
    
    def test_category_assignment(self):
        """Test that activities are assigned to the correct categories."""
        # Authentication activities
        auth_actions = ['login', 'logout', 'password_change', 'password_reset', 'account_verified']
        for action in auth_actions:
            activity = log_user_activity(user=self.user, action=action)
            self.assertEqual(activity.category.code, 'authentication')
        
        # User management activities
        user_mgmt_actions = ['profile_update', 'update']
        for action in user_mgmt_actions:
            activity = log_user_activity(user=self.user, action=action)
            self.assertEqual(activity.category.code, 'user_management')
        
        # General activities
        general_actions = ['create', 'read', 'delete', 'export', 'import', 'admin']
        for action in general_actions:
            activity = log_user_activity(user=self.user, action=action)
            self.assertEqual(activity.category.code, 'general')
    
    def test_content_type_handling(self):
        """Test handling of content types and object references."""
        # Test with valid content type
        user_content_type = ContentType.objects.get_for_model(User)
        activity = log_user_activity(
            user=self.user,
            action='update',
            object_type=f'{user_content_type.app_label}.{user_content_type.model}',
            object_id=self.user.id,
            object_repr=str(self.user)
        )
        
        self.assertEqual(activity.content_type, user_content_type)
        self.assertEqual(activity.object_id, self.user.id)
        
        # Test with invalid content type (should store in metadata)
        activity = log_user_activity(
            user=self.user,
            action='update',
            object_type='invalid.model',
            object_id=999,
            object_repr='Invalid Object'
        )
        
        self.assertIsNone(activity.content_type)
        self.assertIsNone(activity.object_id)
        self.assertIn('original_object_type', activity.metadata)
        self.assertEqual(activity.metadata['original_object_type'], 'invalid.model')
        self.assertEqual(activity.metadata['original_object_id'], 999)
        self.assertEqual(activity.metadata['original_object_repr'], 'Invalid Object')
    
    def test_description_generation(self):
        """Test that descriptions are generated correctly."""
        # Test with object_repr
        activity = log_user_activity(
            user=self.user,
            action='update',
            object_repr='Test Object'
        )
        
        expected_description = f"{self.user.email} - Update: Test Object"
        self.assertEqual(activity.description, expected_description)
        
        # Test without object_repr
        activity = log_user_activity(
            user=self.user,
            action='login'
        )
        
        expected_description = f"{self.user.email} - Login"
        self.assertEqual(activity.description, expected_description)
        
        # Test with system user (None)
        activity = log_user_activity(
            user=None,
            action='admin'
        )
        
        expected_description = "System - Admin"
        self.assertEqual(activity.description, expected_description)
    
    def test_metadata_preservation(self):
        """Test that metadata/details are preserved correctly."""
        details = {
            'method': 'email',
            'user_agent': 'Test Browser',
            'success': True,
            'additional_data': {
                'nested': 'value'
            }
        }
        
        activity = log_user_activity(
            user=self.user,
            action='login',
            details=details
        )
        
        self.assertEqual(activity.metadata, details)
    
    def test_activity_querying(self):
        """Test that activities can be queried like the old UserActivity model."""
        # Create activities
        log_user_activity(user=self.user, action='login')
        log_user_activity(user=self.user, action='logout')
        
        # Create another user and activity
        other_user = User.objects.create_user(
            email='other@example.com',
            username='otheruser',
            password='testpass123'
        )
        log_user_activity(user=other_user, action='login')
        
        # Test filtering by user
        user_activities = Activity.objects.filter(user=self.user)
        self.assertEqual(user_activities.count(), 2)
        
        # Test filtering by action
        login_activities = Activity.objects.filter(action='LOGIN')
        self.assertEqual(login_activities.count(), 2)
        
        # Test ordering
        activities = Activity.objects.order_by('-created_at')
        self.assertEqual(activities.count(), 3)
        
        # Test with select_related (for performance)
        activities = Activity.objects.select_related('user').filter(user=self.user)
        self.assertEqual(activities.count(), 2)
