"""Creative Management Models

Django models for managing creative assets, processing, and optimization.
Handles creative files, versions, formats, templates, and performance tracking.

Models:
- Creative: Main creative entity
- CreativeVersion: Version control
- CreativeFormat: Format specifications
- CreativeTemplate: Reusable templates
- CreativeAsset: Individual asset files
- CreativeApproval: Approval workflow
- CreativePerformance: Performance metrics
- CreativeTag: Tagging system
- CreativeCompliance: Brand safety
- CreativeVariant: A/B testing

Features:
- File upload and processing
- Multi-format transcoding
- Version control
- Approval workflows
- Performance tracking
- Template management
- Compliance checking
"""

import os
import uuid
from decimal import Decimal
from datetime import datetime, timedelta

from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import (
    MinValueValidator, MaxValueValidator, FileExtensionValidator
)
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.urls import reverse

from apps.common.models import BaseModel, AuditModel, StatusModel
from apps.campaigns.models import Campaign

User = get_user_model()


def creative_upload_path(instance, filename):
    """Generate upload path for creative files.
    
    Args:
        instance: Creative instance
        filename: Original filename
        
    Returns:
        str: Upload path
    """
    ext = filename.split('.')[-1]
    filename = f"{uuid.uuid4().hex}.{ext}"
    return f"creatives/{instance.id}/{filename}"


def asset_upload_path(instance, filename):
    """Generate upload path for asset files.
    
    Args:
        instance: CreativeAsset instance
        filename: Original filename
        
    Returns:
        str: Upload path
    """
    ext = filename.split('.')[-1]
    filename = f"{uuid.uuid4().hex}.{ext}"
    return f"assets/{instance.creative.id}/{instance.asset_type}/{filename}"


def validate_video_file(value):
    """Validate video file format and size.
    
    Args:
        value: File field value
        
    Raises:
        ValidationError: If file is invalid
    """
    if value.size > 500 * 1024 * 1024:  # 500MB limit
        raise ValidationError('Video file size cannot exceed 500MB.')
    
    valid_extensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv']
    ext = value.name.split('.')[-1].lower()
    if ext not in valid_extensions:
        raise ValidationError(f'Invalid video format. Allowed: {", ".join(valid_extensions)}')


def validate_audio_file(value):
    """Validate audio file format and size.
    
    Args:
        value: File field value
        
    Raises:
        ValidationError: If file is invalid
    """
    if value.size > 50 * 1024 * 1024:  # 50MB limit
        raise ValidationError('Audio file size cannot exceed 50MB.')
    
    valid_extensions = ['mp3', 'wav', 'aac', 'ogg', 'flac', 'm4a']
    ext = value.name.split('.')[-1].lower()
    if ext not in valid_extensions:
        raise ValidationError(f'Invalid audio format. Allowed: {", ".join(valid_extensions)}')


def validate_image_file(value):
    """Validate image file format and size.
    
    Args:
        value: File field value
        
    Raises:
        ValidationError: If file is invalid
    """
    if value.size > 10 * 1024 * 1024:  # 10MB limit
        raise ValidationError('Image file size cannot exceed 10MB.')
    
    valid_extensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
    ext = value.name.split('.')[-1].lower()
    if ext not in valid_extensions:
        raise ValidationError(f'Invalid image format. Allowed: {", ".join(valid_extensions)}')


class Creative(BaseModel, AuditModel, StatusModel):
    """Main creative entity model.
    
    Represents a creative asset with metadata, files, and processing status.
    Supports multiple formats, versions, and approval workflows.
    """
    
    CREATIVE_TYPES = [
        ('video', _('Video')),
        ('audio', _('Audio')),
        ('image', _('Image')),
        ('banner', _('Banner')),
        ('rich_media', _('Rich Media')),
        ('interactive', _('Interactive')),
        ('native', _('Native')),
        ('text', _('Text')),
    ]
    
    CREATIVE_STATUS = [
        ('draft', _('Draft')),
        ('pending_review', _('Pending Review')),
        ('approved', _('Approved')),
        ('rejected', _('Rejected')),
        ('processing', _('Processing')),
        ('ready', _('Ready')),
        ('archived', _('Archived')),
    ]
    
    PRIORITY_LEVELS = [
        (1, _('Low')),
        (2, _('Normal')),
        (3, _('High')),
        (4, _('Urgent')),
        (5, _('Critical')),
    ]
    
    # Basic Information
    name = models.CharField(
        max_length=200,
        verbose_name=_('Creative Name'),
        help_text=_('Descriptive name for the creative')
    )
    
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Detailed description of the creative')
    )
    
    creative_type = models.CharField(
        max_length=20,
        choices=CREATIVE_TYPES,
        verbose_name=_('Creative Type'),
        help_text=_('Type of creative content')
    )
    
    creative_status = models.CharField(
        max_length=20,
        choices=CREATIVE_STATUS,
        default='draft',
        verbose_name=_('Creative Status'),
        help_text=_('Current status of the creative')
    )
    
    # File Information
    primary_file = models.FileField(
        upload_to=creative_upload_path,
        blank=True,
        null=True,
        verbose_name=_('Primary File'),
        help_text=_('Main creative file')
    )
    
    thumbnail = models.ImageField(
        upload_to=creative_upload_path,
        blank=True,
        null=True,
        validators=[validate_image_file],
        verbose_name=_('Thumbnail'),
        help_text=_('Preview thumbnail image')
    )
    
    # Metadata
    duration = models.FloatField(
        blank=True,
        null=True,
        validators=[MinValueValidator(0.1)],
        verbose_name=_('Duration (seconds)'),
        help_text=_('Duration for video/audio content')
    )
    
    file_size = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name=_('File Size (bytes)'),
        help_text=_('Size of the primary file')
    )
    
    dimensions = models.CharField(
        max_length=20,
        blank=True,
        verbose_name=_('Dimensions'),
        help_text=_('Width x Height for visual content')
    )
    
    aspect_ratio = models.CharField(
        max_length=10,
        blank=True,
        verbose_name=_('Aspect Ratio'),
        help_text=_('Aspect ratio (e.g., 16:9)')
    )
    
    # Campaign Association
    campaign = models.ForeignKey(
        Campaign,
        on_delete=models.CASCADE,
        related_name='creatives',
        verbose_name=_('Campaign'),
        help_text=_('Associated campaign')
    )
    
    # Workflow
    priority = models.PositiveIntegerField(
        choices=PRIORITY_LEVELS,
        default=2,
        verbose_name=_('Priority'),
        help_text=_('Processing priority level')
    )
    
    deadline = models.DateTimeField(
        blank=True,
        null=True,
        verbose_name=_('Deadline'),
        help_text=_('Deadline for creative completion')
    )
    
    # Performance Tracking
    impressions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Impressions'),
        help_text=_('Total impressions served')
    )
    
    clicks = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Clicks'),
        help_text=_('Total clicks received')
    )
    
    conversions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Conversions'),
        help_text=_('Total conversions attributed')
    )
    
    # Compliance
    is_compliant = models.BooleanField(
        default=False,
        verbose_name=_('Compliant'),
        help_text=_('Passes brand safety checks')
    )
    
    compliance_score = models.FloatField(
        blank=True,
        null=True,
        validators=[MinValueValidator(0.0), MaxValueValidator(100.0)],
        verbose_name=_('Compliance Score'),
        help_text=_('Brand safety compliance score (0-100)')
    )
    
    class Meta:
        verbose_name = _('Creative')
        verbose_name_plural = _('Creatives')
        db_table = 'creatives_creative'
        ordering = ['-created_at', 'name']
        indexes = [
            models.Index(fields=['campaign', 'creative_status']),
            models.Index(fields=['creative_type', 'status']),
            models.Index(fields=['priority', 'deadline']),
            models.Index(fields=['is_compliant', 'compliance_score']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.get_creative_type_display()})"
    
    def get_absolute_url(self):
        """Get absolute URL for creative detail."""
        return reverse('creatives:creative_detail', kwargs={'pk': self.pk})
    
    @property
    def ctr(self):
        """Calculate click-through rate."""
        if self.impressions > 0:
            return (self.clicks / self.impressions) * 100
        return 0.0
    
    @property
    def conversion_rate(self):
        """Calculate conversion rate."""
        if self.clicks > 0:
            return (self.conversions / self.clicks) * 100
        return 0.0
    
    @property
    def is_overdue(self):
        """Check if creative is overdue."""
        if self.deadline:
            return timezone.now() > self.deadline and self.creative_status != 'ready'
        return False
    
    def get_file_extension(self):
        """Get primary file extension."""
        if self.primary_file:
            return os.path.splitext(self.primary_file.name)[1].lower()
        return ''
    
    def get_file_size_display(self):
        """Get human-readable file size."""
        if not self.file_size:
            return 'Unknown'
        
        for unit in ['B', 'KB', 'MB', 'GB']:
            if self.file_size < 1024.0:
                return f"{self.file_size:.1f} {unit}"
            self.file_size /= 1024.0
        return f"{self.file_size:.1f} TB"
    
    def get_duration_display(self):
        """Get human-readable duration."""
        if not self.duration:
            return 'N/A'
        
        minutes = int(self.duration // 60)
        seconds = int(self.duration % 60)
        
        if minutes > 0:
            return f"{minutes}:{seconds:02d}"
        return f"{seconds}s"


class CreativeVersion(BaseModel, AuditModel):
    """Creative version control model.
    
    Tracks different versions of a creative with change history.
    """
    
    creative = models.ForeignKey(
        Creative,
        on_delete=models.CASCADE,
        related_name='versions',
        verbose_name=_('Creative'),
        help_text=_('Associated creative')
    )
    
    version_number = models.PositiveIntegerField(
        verbose_name=_('Version Number'),
        help_text=_('Sequential version number')
    )
    
    version_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_('Version Name'),
        help_text=_('Descriptive version name')
    )
    
    changes_description = models.TextField(
        verbose_name=_('Changes Description'),
        help_text=_('Description of changes in this version')
    )
    
    file = models.FileField(
        upload_to=creative_upload_path,
        verbose_name=_('Version File'),
        help_text=_('File for this version')
    )
    
    is_current = models.BooleanField(
        default=False,
        verbose_name=_('Current Version'),
        help_text=_('Is this the current active version')
    )
    
    class Meta:
        verbose_name = _('Creative Version')
        verbose_name_plural = _('Creative Versions')
        db_table = 'creatives_version'
        ordering = ['-version_number']
        unique_together = ['creative', 'version_number']
    
    def __str__(self):
        return f"{self.creative.name} v{self.version_number}"


class CreativeFormat(BaseModel, AuditModel, StatusModel):
    """Creative format specifications model.
    
    Defines different format requirements and specifications.
    """
    
    FORMAT_TYPES = [
        ('video', _('Video')),
        ('audio', _('Audio')),
        ('image', _('Image')),
        ('banner', _('Banner')),
    ]
    
    name = models.CharField(
        max_length=100,
        verbose_name=_('Format Name'),
        help_text=_('Name of the format specification')
    )
    
    format_type = models.CharField(
        max_length=20,
        choices=FORMAT_TYPES,
        verbose_name=_('Format Type'),
        help_text=_('Type of format')
    )
    
    width = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name=_('Width (pixels)'),
        help_text=_('Required width in pixels')
    )
    
    height = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name=_('Height (pixels)'),
        help_text=_('Required height in pixels')
    )
    
    max_duration = models.FloatField(
        blank=True,
        null=True,
        validators=[MinValueValidator(0.1)],
        verbose_name=_('Max Duration (seconds)'),
        help_text=_('Maximum allowed duration')
    )
    
    max_file_size = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name=_('Max File Size (bytes)'),
        help_text=_('Maximum allowed file size')
    )
    
    allowed_formats = models.JSONField(
        default=list,
        verbose_name=_('Allowed Formats'),
        help_text=_('List of allowed file formats')
    )
    
    required_specs = models.JSONField(
        default=dict,
        verbose_name=_('Required Specifications'),
        help_text=_('Additional format requirements')
    )
    
    class Meta:
        verbose_name = _('Creative Format')
        verbose_name_plural = _('Creative Formats')
        db_table = 'creatives_format'
        ordering = ['format_type', 'name']
    
    def __str__(self):
        return f"{self.name} ({self.get_format_type_display()})"


class CreativeTemplate(BaseModel, AuditModel, StatusModel):
    """Creative template model.
    
    Reusable templates for creating new creatives.
    """
    
    TEMPLATE_TYPES = [
        ('video', _('Video Template')),
        ('banner', _('Banner Template')),
        ('rich_media', _('Rich Media Template')),
        ('native', _('Native Template')),
    ]
    
    name = models.CharField(
        max_length=100,
        verbose_name=_('Template Name'),
        help_text=_('Name of the template')
    )
    
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Template description')
    )
    
    template_type = models.CharField(
        max_length=20,
        choices=TEMPLATE_TYPES,
        verbose_name=_('Template Type'),
        help_text=_('Type of template')
    )
    
    template_file = models.FileField(
        upload_to='templates/',
        verbose_name=_('Template File'),
        help_text=_('Template file or package')
    )
    
    preview_image = models.ImageField(
        upload_to='templates/previews/',
        blank=True,
        null=True,
        validators=[validate_image_file],
        verbose_name=_('Preview Image'),
        help_text=_('Template preview image')
    )
    
    variables = models.JSONField(
        default=dict,
        verbose_name=_('Template Variables'),
        help_text=_('Configurable template variables')
    )
    
    usage_count = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Usage Count'),
        help_text=_('Number of times template was used')
    )
    
    class Meta:
        verbose_name = _('Creative Template')
        verbose_name_plural = _('Creative Templates')
        db_table = 'creatives_template'
        ordering = ['-usage_count', 'name']
    
    def __str__(self):
        return f"{self.name} ({self.get_template_type_display()})"


class CreativeAsset(BaseModel, AuditModel):
    """Individual creative asset model.
    
    Represents individual files associated with a creative.
    """
    
    ASSET_TYPES = [
        ('video', _('Video')),
        ('audio', _('Audio')),
        ('image', _('Image')),
        ('subtitle', _('Subtitle')),
        ('overlay', _('Overlay')),
        ('logo', _('Logo')),
        ('background', _('Background')),
    ]
    
    creative = models.ForeignKey(
        Creative,
        on_delete=models.CASCADE,
        related_name='assets',
        verbose_name=_('Creative'),
        help_text=_('Associated creative')
    )
    
    asset_type = models.CharField(
        max_length=20,
        choices=ASSET_TYPES,
        verbose_name=_('Asset Type'),
        help_text=_('Type of asset')
    )
    
    name = models.CharField(
        max_length=100,
        verbose_name=_('Asset Name'),
        help_text=_('Name of the asset')
    )
    
    file = models.FileField(
        upload_to=asset_upload_path,
        verbose_name=_('Asset File'),
        help_text=_('Asset file')
    )
    
    file_size = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name=_('File Size (bytes)'),
        help_text=_('Size of the asset file')
    )
    
    metadata = models.JSONField(
        default=dict,
        verbose_name=_('Metadata'),
        help_text=_('Asset metadata and properties')
    )
    
    order = models.PositiveIntegerField(
        default=1,
        verbose_name=_('Display Order'),
        help_text=_('Order for displaying assets')
    )
    
    class Meta:
        verbose_name = _('Creative Asset')
        verbose_name_plural = _('Creative Assets')
        db_table = 'creatives_asset'
        ordering = ['creative', 'order', 'name']
    
    def __str__(self):
        return f"{self.creative.name} - {self.name}"


class CreativeApproval(BaseModel, AuditModel):
    """Creative approval workflow model.
    
    Tracks approval process and decisions.
    """
    
    APPROVAL_STATUS = [
        ('pending', _('Pending')),
        ('approved', _('Approved')),
        ('rejected', _('Rejected')),
        ('changes_requested', _('Changes Requested')),
    ]
    
    creative = models.ForeignKey(
        Creative,
        on_delete=models.CASCADE,
        related_name='approvals',
        verbose_name=_('Creative'),
        help_text=_('Creative being reviewed')
    )
    
    reviewer = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='creative_reviews',
        verbose_name=_('Reviewer'),
        help_text=_('User reviewing the creative')
    )
    
    approval_status = models.CharField(
        max_length=20,
        choices=APPROVAL_STATUS,
        default='pending',
        verbose_name=_('Approval Status'),
        help_text=_('Current approval status')
    )
    
    comments = models.TextField(
        blank=True,
        verbose_name=_('Comments'),
        help_text=_('Reviewer comments and feedback')
    )
    
    reviewed_at = models.DateTimeField(
        blank=True,
        null=True,
        verbose_name=_('Reviewed At'),
        help_text=_('When the review was completed')
    )
    
    class Meta:
        verbose_name = _('Creative Approval')
        verbose_name_plural = _('Creative Approvals')
        db_table = 'creatives_approval'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.creative.name} - {self.get_approval_status_display()}"


class CreativePerformance(BaseModel):
    """Creative performance tracking model.
    
    Stores performance metrics for creatives.
    """
    
    creative = models.ForeignKey(
        Creative,
        on_delete=models.CASCADE,
        related_name='performance_data',
        verbose_name=_('Creative'),
        help_text=_('Creative being tracked')
    )
    
    date = models.DateField(
        verbose_name=_('Date'),
        help_text=_('Performance date')
    )
    
    impressions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Impressions'),
        help_text=_('Number of impressions')
    )
    
    clicks = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Clicks'),
        help_text=_('Number of clicks')
    )
    
    conversions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Conversions'),
        help_text=_('Number of conversions')
    )
    
    spend = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=Decimal('0.00'),
        verbose_name=_('Spend'),
        help_text=_('Amount spent')
    )
    
    revenue = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=Decimal('0.00'),
        verbose_name=_('Revenue'),
        help_text=_('Revenue generated')
    )
    
    class Meta:
        verbose_name = _('Creative Performance')
        verbose_name_plural = _('Creative Performance')
        db_table = 'creatives_performance'
        ordering = ['-date']
        unique_together = ['creative', 'date']
    
    def __str__(self):
        return f"{self.creative.name} - {self.date}"
    
    @property
    def ctr(self):
        """Calculate click-through rate."""
        if self.impressions > 0:
            return (self.clicks / self.impressions) * 100
        return 0.0
    
    @property
    def conversion_rate(self):
        """Calculate conversion rate."""
        if self.clicks > 0:
            return (self.conversions / self.clicks) * 100
        return 0.0
    
    @property
    def roas(self):
        """Calculate return on ad spend."""
        if self.spend > 0:
            return float(self.revenue / self.spend)
        return 0.0


class CreativeTag(BaseModel):
    """Creative tagging model.
    
    Provides tagging and categorization for creatives.
    """
    
    name = models.CharField(
        max_length=50,
        unique=True,
        verbose_name=_('Tag Name'),
        help_text=_('Name of the tag')
    )
    
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Tag description')
    )
    
    color = models.CharField(
        max_length=7,
        default='#007bff',
        verbose_name=_('Color'),
        help_text=_('Tag color (hex code)')
    )
    
    creatives = models.ManyToManyField(
        Creative,
        related_name='tags',
        blank=True,
        verbose_name=_('Creatives'),
        help_text=_('Tagged creatives')
    )
    
    class Meta:
        verbose_name = _('Creative Tag')
        verbose_name_plural = _('Creative Tags')
        db_table = 'creatives_tag'
        ordering = ['name']
    
    def __str__(self):
        return self.name


class CreativeCompliance(BaseModel, AuditModel):
    """Creative compliance tracking model.
    
    Tracks brand safety and compliance checks.
    """
    
    COMPLIANCE_STATUS = [
        ('pending', _('Pending')),
        ('passed', _('Passed')),
        ('failed', _('Failed')),
        ('warning', _('Warning')),
    ]
    
    creative = models.OneToOneField(
        Creative,
        on_delete=models.CASCADE,
        related_name='compliance',
        verbose_name=_('Creative'),
        help_text=_('Creative being checked')
    )
    
    compliance_status = models.CharField(
        max_length=20,
        choices=COMPLIANCE_STATUS,
        default='pending',
        verbose_name=_('Compliance Status'),
        help_text=_('Overall compliance status')
    )
    
    brand_safety_score = models.FloatField(
        blank=True,
        null=True,
        validators=[MinValueValidator(0.0), MaxValueValidator(100.0)],
        verbose_name=_('Brand Safety Score'),
        help_text=_('Brand safety score (0-100)')
    )
    
    content_rating = models.CharField(
        max_length=10,
        blank=True,
        verbose_name=_('Content Rating'),
        help_text=_('Content rating (G, PG, PG-13, R)')
    )
    
    detected_issues = models.JSONField(
        default=list,
        verbose_name=_('Detected Issues'),
        help_text=_('List of detected compliance issues')
    )
    
    scan_results = models.JSONField(
        default=dict,
        verbose_name=_('Scan Results'),
        help_text=_('Detailed scan results')
    )
    
    last_scanned = models.DateTimeField(
        auto_now=True,
        verbose_name=_('Last Scanned'),
        help_text=_('When compliance was last checked')
    )
    
    class Meta:
        verbose_name = _('Creative Compliance')
        verbose_name_plural = _('Creative Compliance')
        db_table = 'creatives_compliance'
        ordering = ['-last_scanned']
    
    def __str__(self):
        return f"{self.creative.name} - {self.get_compliance_status_display()}"


class CreativeVariant(BaseModel, AuditModel, StatusModel):
    """Creative A/B testing variant model.
    
    Manages different variants for A/B testing.
    """
    
    creative = models.ForeignKey(
        Creative,
        on_delete=models.CASCADE,
        related_name='variants',
        verbose_name=_('Creative'),
        help_text=_('Base creative')
    )
    
    variant_name = models.CharField(
        max_length=100,
        verbose_name=_('Variant Name'),
        help_text=_('Name of the variant')
    )
    
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Variant description')
    )
    
    variant_file = models.FileField(
        upload_to=creative_upload_path,
        verbose_name=_('Variant File'),
        help_text=_('Variant creative file')
    )
    
    traffic_allocation = models.FloatField(
        validators=[MinValueValidator(0.0), MaxValueValidator(100.0)],
        default=50.0,
        verbose_name=_('Traffic Allocation (%)'),
        help_text=_('Percentage of traffic for this variant')
    )
    
    # Performance metrics
    impressions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Impressions'),
        help_text=_('Variant impressions')
    )
    
    clicks = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Clicks'),
        help_text=_('Variant clicks')
    )
    
    conversions = models.PositiveIntegerField(
        default=0,
        verbose_name=_('Conversions'),
        help_text=_('Variant conversions')
    )
    
    class Meta:
        verbose_name = _('Creative Variant')
        verbose_name_plural = _('Creative Variants')
        db_table = 'creatives_variant'
        ordering = ['creative', 'variant_name']
        unique_together = ['creative', 'variant_name']
    
    def __str__(self):
        return f"{self.creative.name} - {self.variant_name}"
    
    @property
    def ctr(self):
        """Calculate click-through rate."""
        if self.impressions > 0:
            return (self.clicks / self.impressions) * 100
        return 0.0
    
    @property
    def conversion_rate(self):
        """Calculate conversion rate."""
        if self.clicks > 0:
            return (self.conversions / self.clicks) * 100
        return 0.0
