"""Creative Management Test Suite

Comprehensive test coverage for creative asset management.
Includes unit tests, integration tests, and API tests.

Test Categories:
- Model Tests: Model validation, relationships, methods
- View Tests: HTTP responses, permissions, templates
- API Tests: REST API endpoints, serialization
- Serializer Tests: Data validation, transformation
- Signal Tests: Signal handlers, automation
- Integration Tests: End-to-end workflows
- File Tests: File upload, processing, validation
- Performance Tests: Load testing, optimization
- Security Tests: Authentication, authorization
- Utility Tests: Helper functions, utilities

Test Classes:
- CreativeModelTest: Creative model testing
- CreativeVersionModelTest: Version model testing
- CreativeTemplateModelTest: Template model testing
- CreativeApprovalModelTest: Approval model testing
- CreativePerformanceModelTest: Performance model testing
- CreativeViewTest: View testing
- CreativeAPITest: API endpoint testing
- CreativeSerializerTest: Serializer testing
- CreativeSignalTest: Signal testing
- CreativeIntegrationTest: Integration testing
- FileProcessingTest: File processing testing
- CreativeSecurityTest: Security testing

Features:
- Mock file uploads
- Database transactions
- Cache testing
- Signal testing
- Performance profiling
- Security validation
- Error handling
- Edge case coverage
"""

from django.test import TestCase, TransactionTestCase, override_settings
from django.test.client import Client
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.cache import cache
from django.urls import reverse
from django.db import IntegrityError
from django.utils import timezone
from django.conf import settings

from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from unittest.mock import patch, Mock, MagicMock
from PIL import Image
import tempfile
import os
import json
from datetime import datetime, timedelta
from decimal import Decimal

from .models import (
    Creative, CreativeVersion, CreativeAsset, CreativeApproval,
    CreativePerformance, CreativeCompliance, CreativeTemplate,
    CreativeTag, CreativeVariant, CreativeFormat
)
from .serializers import (
    CreativeSerializer, CreativeDetailSerializer, CreativeCreateSerializer,
    CreativeTemplateSerializer, CreativeApprovalSerializer
)
from .views import (
    CreativeViewSet, CreativeListView, CreativeDetailView,
    creative_upload, approval_dashboard
)
from .utils import (
    validate_creative_file, get_file_metadata, optimize_image,
    generate_thumbnail, clean_filename
)
from .tasks import (
    process_creative_file, extract_metadata, generate_thumbnails,
    check_compliance, update_performance_metrics
)

User = get_user_model()


class CreativeModelTest(TestCase):
    """Test Creative model functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        # Create test image file
        self.test_image = self.create_test_image()
        
        self.creative_data = {
            'name': 'Test Creative',
            'creative_type': 'image',
            'creative_status': 'draft',
            'created_by': self.user,
            'primary_file': self.test_image
        }
    
    def create_test_image(self):
        """Create a test image file."""
        # Create a simple test image
        image = Image.new('RGB', (100, 100), color='red')
        temp_file = tempfile.NamedTemporaryFile(suffix='.jpg', delete=False)
        image.save(temp_file.name, 'JPEG')
        
        with open(temp_file.name, 'rb') as f:
            return SimpleUploadedFile(
                name='test_image.jpg',
                content=f.read(),
                content_type='image/jpeg'
            )
    
    def test_creative_creation(self):
        """Test creative creation."""
        creative = Creative.objects.create(**self.creative_data)
        
        self.assertEqual(creative.name, 'Test Creative')
        self.assertEqual(creative.creative_type, 'image')
        self.assertEqual(creative.creative_status, 'draft')
        self.assertEqual(creative.created_by, self.user)
        self.assertIsNotNone(creative.created_at)
        self.assertIsNotNone(creative.updated_at)
    
    def test_creative_str_representation(self):
        """Test creative string representation."""
        creative = Creative.objects.create(**self.creative_data)
        self.assertEqual(str(creative), 'Test Creative')
    
    def test_creative_slug_generation(self):
        """Test automatic slug generation."""
        creative = Creative.objects.create(**self.creative_data)
        self.assertIsNotNone(creative.slug)
        self.assertTrue(creative.slug.startswith('test-creative'))
    
    def test_creative_file_size_calculation(self):
        """Test file size calculation."""
        creative = Creative.objects.create(**self.creative_data)
        self.assertIsNotNone(creative.file_size)
        self.assertGreater(creative.file_size, 0)
    
    def test_creative_unique_slug(self):
        """Test unique slug generation for duplicate names."""
        creative1 = Creative.objects.create(**self.creative_data)
        
        creative_data2 = self.creative_data.copy()
        creative_data2['primary_file'] = self.create_test_image()
        creative2 = Creative.objects.create(**creative_data2)
        
        self.assertNotEqual(creative1.slug, creative2.slug)
    
    def test_creative_performance_properties(self):
        """Test performance calculation properties."""
        creative = Creative.objects.create(**self.creative_data)
        creative.impressions = 1000
        creative.clicks = 50
        creative.conversions = 5
        creative.save()
        
        self.assertEqual(creative.ctr, 5.0)  # 50/1000 * 100
        self.assertEqual(creative.conversion_rate, 10.0)  # 5/50 * 100
    
    def test_creative_performance_zero_division(self):
        """Test performance calculations with zero values."""
        creative = Creative.objects.create(**self.creative_data)
        creative.impressions = 0
        creative.clicks = 0
        creative.save()
        
        self.assertEqual(creative.ctr, 0)
        self.assertEqual(creative.conversion_rate, 0)
    
    def test_creative_is_active_property(self):
        """Test is_active property."""
        creative = Creative.objects.create(**self.creative_data)
        
        # Test active statuses
        for status in ['approved', 'live']:
            creative.creative_status = status
            creative.save()
            self.assertTrue(creative.is_active)
        
        # Test inactive statuses
        for status in ['draft', 'rejected', 'archived']:
            creative.creative_status = status
            creative.save()
            self.assertFalse(creative.is_active)
    
    def test_creative_get_absolute_url(self):
        """Test get_absolute_url method."""
        creative = Creative.objects.create(**self.creative_data)
        expected_url = f'/creatives/{creative.slug}/'
        self.assertEqual(creative.get_absolute_url(), expected_url)
    
    def tearDown(self):
        """Clean up test files."""
        # Clean up uploaded files
        for creative in Creative.objects.all():
            if creative.primary_file:
                try:
                    os.remove(creative.primary_file.path)
                except:
                    pass


class CreativeVersionModelTest(TestCase):
    """Test CreativeVersion model functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
        
        self.test_file = SimpleUploadedFile(
            name='test_version.jpg',
            content=b'test content',
            content_type='image/jpeg'
        )
    
    def test_version_creation(self):
        """Test version creation."""
        version = CreativeVersion.objects.create(
            creative=self.creative,
            version_number=1,
            file=self.test_file,
            changes='Initial version',
            created_by=self.user
        )
        
        self.assertEqual(version.creative, self.creative)
        self.assertEqual(version.version_number, 1)
        self.assertEqual(version.changes, 'Initial version')
        self.assertEqual(version.created_by, self.user)
    
    def test_version_str_representation(self):
        """Test version string representation."""
        version = CreativeVersion.objects.create(
            creative=self.creative,
            version_number=1,
            file=self.test_file,
            created_by=self.user
        )
        
        expected_str = f'{self.creative.name} - Version 1'
        self.assertEqual(str(version), expected_str)
    
    def test_version_ordering(self):
        """Test version ordering."""
        version1 = CreativeVersion.objects.create(
            creative=self.creative,
            version_number=1,
            file=self.test_file,
            created_by=self.user
        )
        
        version2 = CreativeVersion.objects.create(
            creative=self.creative,
            version_number=2,
            file=self.test_file,
            created_by=self.user
        )
        
        versions = list(CreativeVersion.objects.all())
        self.assertEqual(versions[0], version2)  # Latest first
        self.assertEqual(versions[1], version1)


class CreativeTemplateModelTest(TestCase):
    """Test CreativeTemplate model functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_template_creation(self):
        """Test template creation."""
        template = CreativeTemplate.objects.create(
            name='Test Template',
            template_type='banner',
            width=728,
            height=90,
            created_by=self.user
        )
        
        self.assertEqual(template.name, 'Test Template')
        self.assertEqual(template.template_type, 'banner')
        self.assertEqual(template.width, 728)
        self.assertEqual(template.height, 90)
        self.assertTrue(template.is_active)
    
    def test_template_dimensions_property(self):
        """Test dimensions property."""
        template = CreativeTemplate.objects.create(
            name='Test Template',
            template_type='banner',
            width=728,
            height=90,
            created_by=self.user
        )
        
        self.assertEqual(template.dimensions, '728x90')
    
    def test_template_aspect_ratio_property(self):
        """Test aspect ratio calculation."""
        template = CreativeTemplate.objects.create(
            name='Test Template',
            template_type='banner',
            width=728,
            height=90,
            created_by=self.user
        )
        
        expected_ratio = round(728 / 90, 2)
        self.assertEqual(template.aspect_ratio, expected_ratio)


class CreativeApprovalModelTest(TestCase):
    """Test CreativeApproval model functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.reviewer = User.objects.create_user(
            username='reviewer',
            email='reviewer@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_approval_creation(self):
        """Test approval creation."""
        approval = CreativeApproval.objects.create(
            creative=self.creative,
            reviewer=self.reviewer,
            approval_status='approved',
            comments='Looks good!'
        )
        
        self.assertEqual(approval.creative, self.creative)
        self.assertEqual(approval.reviewer, self.reviewer)
        self.assertEqual(approval.approval_status, 'approved')
        self.assertEqual(approval.comments, 'Looks good!')
    
    def test_approval_str_representation(self):
        """Test approval string representation."""
        approval = CreativeApproval.objects.create(
            creative=self.creative,
            reviewer=self.reviewer,
            approval_status='approved'
        )
        
        expected_str = f'{self.creative.name} - approved by {self.reviewer.username}'
        self.assertEqual(str(approval), expected_str)


class CreativePerformanceModelTest(TestCase):
    """Test CreativePerformance model functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_performance_creation(self):
        """Test performance record creation."""
        performance = CreativePerformance.objects.create(
            creative=self.creative,
            date=timezone.now().date(),
            impressions=1000,
            clicks=50,
            conversions=5,
            cost=Decimal('25.00')
        )
        
        self.assertEqual(performance.creative, self.creative)
        self.assertEqual(performance.impressions, 1000)
        self.assertEqual(performance.clicks, 50)
        self.assertEqual(performance.conversions, 5)
        self.assertEqual(performance.cost, Decimal('25.00'))
    
    def test_performance_calculations(self):
        """Test performance metric calculations."""
        performance = CreativePerformance.objects.create(
            creative=self.creative,
            date=timezone.now().date(),
            impressions=1000,
            clicks=50,
            conversions=5,
            cost=Decimal('25.00')
        )
        
        self.assertEqual(performance.ctr, 5.0)
        self.assertEqual(performance.conversion_rate, 10.0)
        self.assertEqual(performance.cpc, Decimal('0.50'))
        self.assertEqual(performance.cpa, Decimal('5.00'))
        self.assertEqual(performance.cpm, Decimal('25.00'))


class CreativeViewTest(TestCase):
    """Test Creative views."""
    
    def setUp(self):
        """Set up test data."""
        self.client = Client()
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_creative_list_view(self):
        """Test creative list view."""
        self.client.login(username='testuser', password='testpass123')
        
        response = self.client.get(reverse('creatives:creative_list'))
        
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Creative')
        self.assertIn('creatives', response.context)
    
    def test_creative_detail_view(self):
        """Test creative detail view."""
        self.client.login(username='testuser', password='testpass123')
        
        response = self.client.get(
            reverse('creatives:creative_detail', kwargs={'slug': self.creative.slug})
        )
        
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context['creative'], self.creative)
    
    def test_creative_upload_view_get(self):
        """Test creative upload view GET request."""
        self.client.login(username='testuser', password='testpass123')
        
        response = self.client.get(reverse('creatives:creative_upload'))
        
        self.assertEqual(response.status_code, 200)
        self.assertIn('form', response.context)
    
    def test_creative_upload_view_post(self):
        """Test creative upload view POST request."""
        self.client.login(username='testuser', password='testpass123')
        
        # Create test file
        test_file = SimpleUploadedFile(
            name='test_upload.jpg',
            content=b'test content',
            content_type='image/jpeg'
        )
        
        data = {
            'name': 'Uploaded Creative',
            'creative_type': 'image',
            'primary_file': test_file
        }
        
        response = self.client.post(reverse('creatives:creative_upload'), data)
        
        # Should redirect after successful upload
        self.assertEqual(response.status_code, 302)
        
        # Check creative was created
        self.assertTrue(
            Creative.objects.filter(name='Uploaded Creative').exists()
        )
    
    def test_approval_dashboard_view(self):
        """Test approval dashboard view."""
        self.client.login(username='testuser', password='testpass123')
        
        response = self.client.get(reverse('creatives:approval_dashboard'))
        
        self.assertEqual(response.status_code, 200)
        self.assertIn('pending_creatives', response.context)
    
    def test_unauthorized_access(self):
        """Test unauthorized access to views."""
        # Test without login
        response = self.client.get(reverse('creatives:creative_list'))
        self.assertEqual(response.status_code, 302)  # Redirect to login


class CreativeAPITest(APITestCase):
    """Test Creative API endpoints."""
    
    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_creative_list_api(self):
        """Test creative list API endpoint."""
        self.client.force_authenticate(user=self.user)
        
        response = self.client.get('/api/creatives/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)
        self.assertEqual(response.data['results'][0]['name'], 'Test Creative')
    
    def test_creative_detail_api(self):
        """Test creative detail API endpoint."""
        self.client.force_authenticate(user=self.user)
        
        response = self.client.get(f'/api/creatives/{self.creative.pk}/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], 'Test Creative')
    
    def test_creative_create_api(self):
        """Test creative creation via API."""
        self.client.force_authenticate(user=self.user)
        
        data = {
            'name': 'API Creative',
            'creative_type': 'image',
            'creative_status': 'draft'
        }
        
        response = self.client.post('/api/creatives/', data)
        
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], 'API Creative')
        
        # Check creative was created in database
        self.assertTrue(
            Creative.objects.filter(name='API Creative').exists()
        )
    
    def test_creative_update_api(self):
        """Test creative update via API."""
        self.client.force_authenticate(user=self.user)
        
        data = {
            'name': 'Updated Creative',
            'creative_type': 'image',
            'creative_status': 'approved'
        }
        
        response = self.client.put(f'/api/creatives/{self.creative.pk}/', data)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], 'Updated Creative')
        
        # Check creative was updated in database
        self.creative.refresh_from_db()
        self.assertEqual(self.creative.name, 'Updated Creative')
    
    def test_creative_delete_api(self):
        """Test creative deletion via API."""
        self.client.force_authenticate(user=self.user)
        
        response = self.client.delete(f'/api/creatives/{self.creative.pk}/')
        
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        
        # Check creative was deleted from database
        self.assertFalse(
            Creative.objects.filter(pk=self.creative.pk).exists()
        )
    
    def test_unauthorized_api_access(self):
        """Test unauthorized API access."""
        # Test without authentication
        response = self.client.get('/api/creatives/')
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)


class CreativeSerializerTest(TestCase):
    """Test Creative serializers."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_creative_serializer(self):
        """Test CreativeSerializer."""
        serializer = CreativeSerializer(instance=self.creative)
        data = serializer.data
        
        self.assertEqual(data['name'], 'Test Creative')
        self.assertEqual(data['creative_type'], 'image')
        self.assertIn('created_at', data)
        self.assertIn('updated_at', data)
    
    def test_creative_detail_serializer(self):
        """Test CreativeDetailSerializer."""
        serializer = CreativeDetailSerializer(instance=self.creative)
        data = serializer.data
        
        self.assertEqual(data['name'], 'Test Creative')
        self.assertIn('versions', data)
        self.assertIn('assets', data)
        self.assertIn('performance_data', data)
    
    def test_creative_create_serializer_validation(self):
        """Test CreativeCreateSerializer validation."""
        # Test valid data
        valid_data = {
            'name': 'New Creative',
            'creative_type': 'image',
            'creative_status': 'draft'
        }
        
        serializer = CreativeCreateSerializer(data=valid_data)
        self.assertTrue(serializer.is_valid())
        
        # Test invalid data
        invalid_data = {
            'name': '',  # Empty name
            'creative_type': 'invalid_type',  # Invalid type
        }
        
        serializer = CreativeCreateSerializer(data=invalid_data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('name', serializer.errors)
        self.assertIn('creative_type', serializer.errors)


class CreativeSignalTest(TransactionTestCase):
    """Test Creative signals."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    @patch('creatives.tasks.process_creative_file.delay')
    def test_creative_post_save_signal(self, mock_task):
        """Test creative post_save signal."""
        # Create test file
        test_file = SimpleUploadedFile(
            name='test_signal.jpg',
            content=b'test content',
            content_type='image/jpeg'
        )
        
        creative = Creative.objects.create(
            name='Signal Test Creative',
            creative_type='image',
            primary_file=test_file,
            created_by=self.user
        )
        
        # Check that processing task was called
        mock_task.assert_called_once_with(creative.pk)
    
    def test_creative_pre_delete_signal(self):
        """Test creative pre_delete signal."""
        creative = Creative.objects.create(
            name='Delete Test Creative',
            creative_type='image',
            created_by=self.user
        )
        
        creative_id = creative.pk
        creative.delete()
        
        # Check that creative was deleted
        self.assertFalse(
            Creative.objects.filter(pk=creative_id).exists()
        )


class CreativeIntegrationTest(TransactionTestCase):
    """Test Creative integration workflows."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.reviewer = User.objects.create_user(
            username='reviewer',
            email='reviewer@example.com',
            password='testpass123'
        )
    
    def test_creative_approval_workflow(self):
        """Test complete creative approval workflow."""
        # 1. Create creative
        creative = Creative.objects.create(
            name='Workflow Test Creative',
            creative_type='image',
            creative_status='draft',
            created_by=self.user
        )
        
        self.assertEqual(creative.creative_status, 'draft')
        
        # 2. Submit for approval
        creative.creative_status = 'pending_approval'
        creative.save()
        
        self.assertEqual(creative.creative_status, 'pending_approval')
        
        # 3. Create approval record
        approval = CreativeApproval.objects.create(
            creative=creative,
            reviewer=self.reviewer,
            approval_status='approved',
            comments='Approved for use'
        )
        
        # 4. Check creative status updated
        creative.refresh_from_db()
        self.assertEqual(creative.creative_status, 'approved')
        
        # 5. Check approval record
        self.assertEqual(approval.approval_status, 'approved')
        self.assertEqual(approval.reviewer, self.reviewer)
    
    def test_creative_performance_tracking(self):
        """Test creative performance tracking workflow."""
        # 1. Create creative
        creative = Creative.objects.create(
            name='Performance Test Creative',
            creative_type='image',
            creative_status='live',
            created_by=self.user
        )
        
        # 2. Add performance data
        performance = CreativePerformance.objects.create(
            creative=creative,
            date=timezone.now().date(),
            impressions=1000,
            clicks=50,
            conversions=5,
            cost=Decimal('25.00')
        )
        
        # 3. Check performance calculations
        self.assertEqual(performance.ctr, 5.0)
        self.assertEqual(performance.conversion_rate, 10.0)
        
        # 4. Update creative aggregate performance
        creative.impressions = performance.impressions
        creative.clicks = performance.clicks
        creative.conversions = performance.conversions
        creative.save()
        
        # 5. Check creative performance properties
        self.assertEqual(creative.ctr, 5.0)
        self.assertEqual(creative.conversion_rate, 10.0)


class FileProcessingTest(TestCase):
    """Test file processing functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def create_test_image_file(self, width=100, height=100, format='JPEG'):
        """Create a test image file."""
        image = Image.new('RGB', (width, height), color='red')
        temp_file = tempfile.NamedTemporaryFile(suffix='.jpg', delete=False)
        image.save(temp_file.name, format)
        
        with open(temp_file.name, 'rb') as f:
            content = f.read()
        
        os.unlink(temp_file.name)
        
        return SimpleUploadedFile(
            name='test_image.jpg',
            content=content,
            content_type='image/jpeg'
        )
    
    def test_file_validation(self):
        """Test file validation."""
        # Test valid image file
        valid_file = self.create_test_image_file()
        
        is_valid, error = validate_creative_file(valid_file)
        self.assertTrue(is_valid)
        self.assertIsNone(error)
        
        # Test invalid file type
        invalid_file = SimpleUploadedFile(
            name='test.txt',
            content=b'text content',
            content_type='text/plain'
        )
        
        is_valid, error = validate_creative_file(invalid_file)
        self.assertFalse(is_valid)
        self.assertIsNotNone(error)
    
    def test_metadata_extraction(self):
        """Test metadata extraction."""
        test_file = self.create_test_image_file(width=200, height=150)
        
        metadata = get_file_metadata(test_file)
        
        self.assertIn('width', metadata)
        self.assertIn('height', metadata)
        self.assertIn('format', metadata)
        self.assertIn('file_size', metadata)
    
    @patch('creatives.utils.Image.open')
    def test_thumbnail_generation(self, mock_image_open):
        """Test thumbnail generation."""
        # Mock PIL Image
        mock_image = Mock()
        mock_image.size = (200, 150)
        mock_image_open.return_value = mock_image
        
        test_file = self.create_test_image_file()
        
        thumbnail = generate_thumbnail(test_file, size=(100, 100))
        
        # Check that thumbnail processing was attempted
        mock_image_open.assert_called_once()
    
    def test_filename_cleaning(self):
        """Test filename cleaning utility."""
        # Test various filename scenarios
        test_cases = [
            ('test file.jpg', 'test_file.jpg'),
            ('Test File!@#.jpg', 'test_file.jpg'),
            ('file with spaces.png', 'file_with_spaces.png'),
            ('UPPERCASE.JPG', 'uppercase.jpg')
        ]
        
        for original, expected in test_cases:
            cleaned = clean_filename(original)
            self.assertEqual(cleaned, expected)


class CreativeSecurityTest(TestCase):
    """Test Creative security features."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.other_user = User.objects.create_user(
            username='otheruser',
            email='other@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Security Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    def test_creative_ownership_permissions(self):
        """Test creative ownership permissions."""
        # Owner should be able to access
        self.assertEqual(self.creative.created_by, self.user)
        
        # Other user should not be able to modify
        # (This would be enforced in views/serializers)
        self.assertNotEqual(self.creative.created_by, self.other_user)
    
    def test_file_upload_security(self):
        """Test file upload security."""
        # Test malicious file upload attempt
        malicious_file = SimpleUploadedFile(
            name='malicious.php',
            content=b'<?php echo "hack"; ?>',
            content_type='application/x-php'
        )
        
        is_valid, error = validate_creative_file(malicious_file)
        self.assertFalse(is_valid)
        self.assertIn('file type', error.lower())
    
    def test_sql_injection_protection(self):
        """Test SQL injection protection."""
        # Test malicious input in creative name
        malicious_name = "'; DROP TABLE creatives_creative; --"
        
        creative = Creative.objects.create(
            name=malicious_name,
            creative_type='image',
            created_by=self.user
        )
        
        # Should be safely stored
        self.assertEqual(creative.name, malicious_name)
        
        # Database should still exist
        self.assertTrue(Creative.objects.filter(pk=creative.pk).exists())


class CreativeUtilityTest(TestCase):
    """Test Creative utility functions."""
    
    def test_file_size_formatting(self):
        """Test file size formatting utility."""
        from .utils import format_file_size
        
        test_cases = [
            (1024, '1.0 KB'),
            (1048576, '1.0 MB'),
            (1073741824, '1.0 GB'),
            (500, '500 B')
        ]
        
        for size, expected in test_cases:
            formatted = format_file_size(size)
            self.assertEqual(formatted, expected)
    
    def test_mime_type_detection(self):
        """Test MIME type detection."""
        from .utils import get_mime_type
        
        test_cases = [
            ('test.jpg', 'image/jpeg'),
            ('test.png', 'image/png'),
            ('test.mp4', 'video/mp4'),
            ('test.pdf', 'application/pdf')
        ]
        
        for filename, expected_mime in test_cases:
            mime_type = get_mime_type(filename)
            self.assertEqual(mime_type, expected_mime)
    
    def test_upload_path_generation(self):
        """Test upload path generation."""
        from .utils import creative_upload_path
        
        creative = Creative(
            name='Test Creative',
            creative_type='image'
        )
        
        filename = 'test_image.jpg'
        path = creative_upload_path(creative, filename)
        
        # Should include year/month structure
        self.assertIn(str(timezone.now().year), path)
        self.assertIn(filename, path)


class CreativePerformanceTest(TestCase):
    """Test Creative performance and optimization."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_bulk_creative_creation(self):
        """Test bulk creative creation performance."""
        import time
        
        start_time = time.time()
        
        # Create 100 creatives
        creatives = []
        for i in range(100):
            creatives.append(Creative(
                name=f'Bulk Creative {i}',
                creative_type='image',
                created_by=self.user
            ))
        
        Creative.objects.bulk_create(creatives)
        
        end_time = time.time()
        creation_time = end_time - start_time
        
        # Should complete within reasonable time
        self.assertLess(creation_time, 5.0)  # 5 seconds
        
        # Check all creatives were created
        self.assertEqual(Creative.objects.count(), 100)
    
    def test_query_optimization(self):
        """Test query optimization."""
        # Create test data
        for i in range(10):
            creative = Creative.objects.create(
                name=f'Query Test Creative {i}',
                creative_type='image',
                created_by=self.user
            )
            
            # Add performance data
            CreativePerformance.objects.create(
                creative=creative,
                date=timezone.now().date(),
                impressions=1000 + i,
                clicks=50 + i,
                conversions=5 + i
            )
        
        # Test optimized query with select_related/prefetch_related
        with self.assertNumQueries(3):  # Should be minimal queries
            creatives = Creative.objects.select_related('created_by').prefetch_related(
                'performance_data'
            ).all()
            
            # Access related data
            for creative in creatives:
                _ = creative.created_by.username
                _ = list(creative.performance_data.all())
    
    @override_settings(CACHES={
        'default': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        }
    })
    def test_cache_performance(self):
        """Test cache performance."""
        creative = Creative.objects.create(
            name='Cache Test Creative',
            creative_type='image',
            created_by=self.user
        )
        
        cache_key = f'creative_{creative.pk}'
        
        # Test cache miss
        cached_creative = cache.get(cache_key)
        self.assertIsNone(cached_creative)
        
        # Set cache
        cache.set(cache_key, creative, 300)
        
        # Test cache hit
        cached_creative = cache.get(cache_key)
        self.assertEqual(cached_creative.pk, creative.pk)
        
        # Test cache invalidation
        cache.delete(cache_key)
        cached_creative = cache.get(cache_key)
        self.assertIsNone(cached_creative)


class CreativeTaskTest(TestCase):
    """Test Creative Celery tasks."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.creative = Creative.objects.create(
            name='Task Test Creative',
            creative_type='image',
            created_by=self.user
        )
    
    @patch('creatives.tasks.extract_metadata')
    def test_process_creative_file_task(self, mock_extract):
        """Test process_creative_file task."""
        from .tasks import process_creative_file
        
        # Mock the task execution
        mock_extract.return_value = {
            'width': 200,
            'height': 150,
            'format': 'JPEG'
        }
        
        # Execute task
        result = process_creative_file(self.creative.pk)
        
        # Check task completed
        self.assertTrue(result)
    
    @patch('creatives.tasks.send_mail')
    def test_send_approval_notification_task(self, mock_send_mail):
        """Test send_approval_notification task."""
        from .tasks import send_approval_notification
        
        # Execute task
        send_approval_notification(
            self.creative.pk,
            'approved',
            self.user.pk,
            'Looks good!'
        )
        
        # Check email was sent
        mock_send_mail.assert_called_once()
    
    def test_update_performance_metrics_task(self):
        """Test update_performance_metrics task."""
        from .tasks import update_performance_metrics
        
        # Create performance data
        CreativePerformance.objects.create(
            creative=self.creative,
            date=timezone.now().date(),
            impressions=1000,
            clicks=50,
            conversions=5
        )
        
        # Execute task
        result = update_performance_metrics(self.creative.pk)
        
        # Check task completed
        self.assertTrue(result)
        
        # Check creative was updated
        self.creative.refresh_from_db()
        self.assertEqual(self.creative.impressions, 1000)
        self.assertEqual(self.creative.clicks, 50)
        self.assertEqual(self.creative.conversions, 5)