"""Adspots models for managing advertising spots and creative content.

This module defines models for:
- Adspots: Individual advertising spots with media files
- AdspotsInAvail: Association between adspots and availability windows
- Avails: Advertising availability windows
- Windows: Time windows for ad placement
- Pending: Pending creative content for processing
"""

import uuid
from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import FileExtensionValidator
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from apps.core.models import BaseModel, AuditModel, StatusModel
from apps.campaigns.models import Campaign
from apps.channels.models import Channel
from apps.advertisers.models import Brand


User = get_user_model()


def adspot_upload_path(instance, filename):
    """Generate upload path for adspot files."""
    ext = filename.split('.')[-1]
    filename = f"{uuid.uuid4().hex}.{ext}"
    return f"adspots/{instance.id}/{filename}"


class Adspot(BaseModel, AuditModel, StatusModel):
    """Advertising spot model.
    
    Represents individual advertising spots with their media files,
    duration, and association with campaigns and brands.
    
    Attributes:
        name (str): Adspot name/identifier
        campaign (ForeignKey): Associated campaign
        brand (ForeignKey): Associated brand
        channel (ForeignKey): Associated channel
        original_file (FileField): Original media file
        encoded_file (FileField): Encoded/processed media file
        duration (str): Duration of the adspot
        filename (str): Original filename
        creative_id (str): Creative identifier
        vast_url (str): VAST URL for ad serving
        file_size (int): File size in bytes
        format (str): Media format
        resolution (str): Video resolution
        bitrate (int): Media bitrate
        frame_rate (float): Video frame rate
        audio_codec (str): Audio codec used
        video_codec (str): Video codec used
        md5_hash (str): MD5 hash of the file
        is_processed (bool): Whether file has been processed
        processing_status (str): Current processing status
        error_message (str): Error message if processing failed
    """
    
    PROCESSING_STATUS_CHOICES = [
        ('pending', _('Pending')),
        ('processing', _('Processing')),
        ('completed', _('Completed')),
        ('failed', _('Failed')),
        ('cancelled', _('Cancelled')),
    ]
    
    FORMAT_CHOICES = [
        ('mp4', 'MP4'),
        ('avi', 'AVI'),
        ('mov', 'MOV'),
        ('wmv', 'WMV'),
        ('flv', 'FLV'),
        ('webm', 'WebM'),
        ('mkv', 'MKV'),
        ('ts', 'MPEG-TS'),
        ('mp3', 'MP3'),
        ('wav', 'WAV'),
        ('aac', 'AAC'),
    ]
    
    # Basic Information
    name = models.CharField(
        max_length=255,
        verbose_name=_('Adspot Name'),
        help_text=_('Name or identifier for the advertising spot')
    )
    
    # Relationships
    campaign = models.ForeignKey(
        Campaign,
        on_delete=models.CASCADE,
        related_name='adspots',
        null=True,
        blank=True,
        verbose_name=_('Campaign'),
        help_text=_('Associated campaign')
    )
    
    brand = models.ForeignKey(
        Brand,
        on_delete=models.CASCADE,
        related_name='adspots',
        null=True,
        blank=True,
        verbose_name=_('Brand'),
        help_text=_('Associated brand')
    )
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='adspots',
        null=True,
        blank=True,
        verbose_name=_('Channel'),
        help_text=_('Associated channel')
    )
    
    # File Information
    original_file = models.FileField(
        upload_to=adspot_upload_path,
        validators=[FileExtensionValidator(
            allowed_extensions=['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv', 'ts', 'mp3', 'wav', 'aac']
        )],
        verbose_name=_('Original File'),
        help_text=_('Original media file')
    )
    
    encoded_file = models.FileField(
        upload_to=adspot_upload_path,
        null=True,
        blank=True,
        verbose_name=_('Encoded File'),
        help_text=_('Processed/encoded media file')
    )
    
    duration = models.CharField(
        max_length=20,
        null=True,
        blank=True,
        verbose_name=_('Duration'),
        help_text=_('Duration of the adspot (e.g., 00:00:30)')
    )
    
    filename = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Filename'),
        help_text=_('Original filename')
    )
    
    creative_id = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Creative ID'),
        help_text=_('Creative identifier')
    )
    
    vast_url = models.URLField(
        null=True,
        blank=True,
        verbose_name=_('VAST URL'),
        help_text=_('VAST URL for ad serving')
    )
    
    # Technical Information
    file_size = models.BigIntegerField(
        null=True,
        blank=True,
        verbose_name=_('File Size'),
        help_text=_('File size in bytes')
    )
    
    format = models.CharField(
        max_length=10,
        choices=FORMAT_CHOICES,
        null=True,
        blank=True,
        verbose_name=_('Format'),
        help_text=_('Media format')
    )
    
    resolution = models.CharField(
        max_length=20,
        null=True,
        blank=True,
        verbose_name=_('Resolution'),
        help_text=_('Video resolution (e.g., 1920x1080)')
    )
    
    bitrate = models.IntegerField(
        null=True,
        blank=True,
        verbose_name=_('Bitrate'),
        help_text=_('Media bitrate in kbps')
    )
    
    frame_rate = models.FloatField(
        null=True,
        blank=True,
        verbose_name=_('Frame Rate'),
        help_text=_('Video frame rate (e.g., 25.0, 29.97)')
    )
    
    audio_codec = models.CharField(
        max_length=20,
        null=True,
        blank=True,
        verbose_name=_('Audio Codec'),
        help_text=_('Audio codec used')
    )
    
    video_codec = models.CharField(
        max_length=20,
        null=True,
        blank=True,
        verbose_name=_('Video Codec'),
        help_text=_('Video codec used')
    )
    
    md5_hash = models.CharField(
        max_length=32,
        null=True,
        blank=True,
        verbose_name=_('MD5 Hash'),
        help_text=_('MD5 hash of the file for integrity checking')
    )
    
    # Processing Information
    is_processed = models.BooleanField(
        default=False,
        verbose_name=_('Is Processed'),
        help_text=_('Whether the file has been processed')
    )
    
    processing_status = models.CharField(
        max_length=20,
        choices=PROCESSING_STATUS_CHOICES,
        default='pending',
        verbose_name=_('Processing Status'),
        help_text=_('Current processing status')
    )
    
    error_message = models.TextField(
        null=True,
        blank=True,
        verbose_name=_('Error Message'),
        help_text=_('Error message if processing failed')
    )
    
    class Meta:
        db_table = 'adspots'
        verbose_name = _('Ad Spot')
        verbose_name_plural = _('Ad Spots')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['name']),
            models.Index(fields=['creative_id']),
            models.Index(fields=['processing_status']),
            models.Index(fields=['created_at']),
        ]
    
    def __str__(self):
        return self.name
    
    def get_impressions(self, start_date=None, end_date=None):
        """Get impression statistics for this adspot."""
        from apps.analytics.models import VastResponse
        
        queryset = VastResponse.objects.filter(ad_spot=self)
        
        if start_date:
            queryset = queryset.filter(datetime_timestamp__gte=start_date)
        if end_date:
            queryset = queryset.filter(datetime_timestamp__lte=end_date)
        
        return {
            'total_requests': queryset.count(),
            'successful_impressions': queryset.filter(
                impression_sprintserve_status__isnull=False
            ).count(),
            'completion_rate': queryset.filter(
                tracking_completed_status__isnull=False
            ).count(),
        }


class Avail(BaseModel, AuditModel):
    """Advertising availability window model.
    
    Represents time windows when advertising spots can be placed.
    
    Attributes:
        window (ForeignKey): Associated time window
        avail_start (str): Start time of the availability
        avail_in_window (str): Position within the window
    """
    
    window = models.ForeignKey(
        'Window',
        on_delete=models.CASCADE,
        related_name='avails',
        null=True,
        blank=True,
        verbose_name=_('Window'),
        help_text=_('Associated time window')
    )
    
    avail_start = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Avail Start'),
        help_text=_('Start time of the availability')
    )
    
    avail_in_window = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Avail in Window'),
        help_text=_('Position within the window')
    )
    
    class Meta:
        db_table = 'avails'
        verbose_name = _('Avail')
        verbose_name_plural = _('Avails')
        ordering = ['avail_start']
    
    def __str__(self):
        return f"Avail {self.id} - {self.avail_start}"


class Window(BaseModel, AuditModel):
    """Time window model for ad placement.
    
    Represents time windows during which ads can be placed.
    
    Attributes:
        playlist (ForeignKey): Associated playlist
        window_start (str): Window start time
        window_end (str): Window end time
        window_duration (str): Duration of the window
    """
    
    playlist = models.ForeignKey(
        'playlists.Playlist',
        on_delete=models.CASCADE,
        related_name='windows',
        null=True,
        blank=True,
        verbose_name=_('Playlist'),
        help_text=_('Associated playlist')
    )
    
    window_start = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Window Start'),
        help_text=_('Start time of the window')
    )
    
    window_end = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Window End'),
        help_text=_('End time of the window')
    )
    
    window_duration = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('Window Duration'),
        help_text=_('Duration of the window')
    )
    
    class Meta:
        db_table = 'windows'
        verbose_name = _('Window')
        verbose_name_plural = _('Windows')
        ordering = ['window_start']
    
    def __str__(self):
        return f"Window {self.id} - {self.window_start} to {self.window_end}"


class AdspotInAvail(BaseModel, AuditModel):
    """Association between adspots and availability windows.
    
    Represents the placement of adspots within specific availability windows.
    
    Attributes:
        avail (ForeignKey): Associated availability window
        adspot (ForeignKey): Associated adspot
        position_in_avail (int): Position within the availability
        traffic_id (int): Traffic system identifier
    """
    
    avail = models.ForeignKey(
        Avail,
        on_delete=models.CASCADE,
        related_name='adspot_placements',
        verbose_name=_('Avail'),
        help_text=_('Associated availability window')
    )
    
    adspot = models.ForeignKey(
        Adspot,
        on_delete=models.CASCADE,
        related_name='avail_placements',
        verbose_name=_('Adspot'),
        help_text=_('Associated adspot')
    )
    
    position_in_avail = models.IntegerField(
        null=True,
        blank=True,
        verbose_name=_('Position in Avail'),
        help_text=_('Position within the availability window')
    )
    
    traffic_id = models.IntegerField(
        null=True,
        blank=True,
        verbose_name=_('Traffic ID'),
        help_text=_('Traffic system identifier')
    )
    
    class Meta:
        db_table = 'adspots_in_avail'
        verbose_name = _('Adspot in Avail')
        verbose_name_plural = _('Adspots in Avails')
        unique_together = ['avail', 'position_in_avail']
        ordering = ['avail', 'position_in_avail']
    
    def __str__(self):
        return f"{self.adspot.name} in {self.avail} at position {self.position_in_avail}"


class Pending(BaseModel, AuditModel):
    """Pending creative content model.
    
    Represents creative content that is pending processing or approval.
    
    Attributes:
        creative_id (str): Creative identifier
        url (str): URL to the creative content
        duration (str): Duration of the creative
        status (str): Processing status
        error_message (str): Error message if processing failed
    """
    
    PENDING_STATUS_CHOICES = [
        ('pending', _('Pending')),
        ('processing', _('Processing')),
        ('approved', _('Approved')),
        ('rejected', _('Rejected')),
        ('failed', _('Failed')),
    ]
    
    creative_id = models.CharField(
        max_length=255,
        verbose_name=_('Creative ID'),
        help_text=_('Creative identifier')
    )
    
    url = models.URLField(
        verbose_name=_('URL'),
        help_text=_('URL to the creative content')
    )
    
    duration = models.CharField(
        max_length=20,
        null=True,
        blank=True,
        verbose_name=_('Duration'),
        help_text=_('Duration of the creative')
    )
    
    status = models.CharField(
        max_length=20,
        choices=PENDING_STATUS_CHOICES,
        default='pending',
        verbose_name=_('Status'),
        help_text=_('Processing status')
    )
    
    error_message = models.TextField(
        null=True,
        blank=True,
        verbose_name=_('Error Message'),
        help_text=_('Error message if processing failed')
    )
    
    class Meta:
        db_table = 'pending'
        verbose_name = _('Pending Creative')
        verbose_name_plural = _('Pending Creatives')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['creative_id']),
            models.Index(fields=['status']),
            models.Index(fields=['created_at']),
        ]
    
    def __str__(self):
        return f"Pending {self.creative_id} - {self.status}"