from django.db import models
from django.core.validators import RegexValidator, MinValueValidator, MaxValueValidator
from django.utils import timezone
from apps.core.models import BaseModel
from apps.accounts.models import User
import uuid


class Codec(BaseModel):
    """
    Model representing video/audio codecs used by TV channels.
    
    Codecs define the encoding format for video and audio streams.
    Each channel can use different codecs for different distribution zones.
    """
    CODEC_TYPE_CHOICES = [
        ('video', 'Video Codec'),
        ('audio', 'Audio Codec'),
        ('container', 'Container Format'),
    ]
    
    name = models.CharField(
        max_length=100, 
        unique=True,
        help_text="Name of the codec (e.g., H.264, AAC, MP4)"
    )
    codec_type = models.CharField(
        max_length=20, 
        choices=CODEC_TYPE_CHOICES,
        help_text="Type of codec: video, audio, or container"
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the codec and its properties"
    )
    mime_type = models.CharField(
        max_length=100, 
        blank=True,
        help_text="MIME type for the codec (e.g., video/mp4, audio/aac)"
    )
    bitrate_min = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Minimum bitrate in kbps"
    )
    bitrate_max = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Maximum bitrate in kbps"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this codec is currently available for use"
    )
    
    class Meta:
        db_table = 'channels_codec'
        verbose_name = 'Codec'
        verbose_name_plural = 'Codecs'
        ordering = ['codec_type', 'name']
        indexes = [
            models.Index(fields=['codec_type']),
            models.Index(fields=['is_active']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.get_codec_type_display()})"
    
    def clean(self):
        """
        Validate that bitrate_max is greater than bitrate_min if both are provided.
        """
        from django.core.exceptions import ValidationError
        if self.bitrate_min and self.bitrate_max:
            if self.bitrate_max <= self.bitrate_min:
                raise ValidationError('Maximum bitrate must be greater than minimum bitrate.')


class Zone(BaseModel):
    """
    Model representing geographical or logical distribution zones.
    
    Zones define where channels can be distributed and help manage
    regional content delivery and codec requirements.
    """
    name = models.CharField(
        max_length=100, 
        unique=True,
        help_text="Name of the distribution zone (e.g., North America, Europe)"
    )
    code = models.CharField(
        max_length=10, 
        unique=True,
        validators=[
            RegexValidator(
                regex=r'^[A-Z0-9_]+$',
                message='Zone code must contain only uppercase letters, numbers, and underscores.'
            )
        ],
        help_text="Short code for the zone (e.g., NA, EU, ASIA)"
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the zone coverage and characteristics"
    )
    timezone = models.CharField(
        max_length=50, 
        default='UTC',
        help_text="Primary timezone for this zone"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this zone is currently active for distribution"
    )
    
    class Meta:
        db_table = 'channels_zone'
        verbose_name = 'Distribution Zone'
        verbose_name_plural = 'Distribution Zones'
        ordering = ['name']
        indexes = [
            models.Index(fields=['code']),
            models.Index(fields=['is_active']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.code})"


class Channel(BaseModel):
    """
    Model representing a TV channel.
    
    Channels are the main broadcasting entities that can be distributed
    across multiple zones with different codec configurations.
    """
    CHANNEL_TYPE_CHOICES = [
        ('terrestrial', 'Terrestrial'),
        ('satellite', 'Satellite'),
        ('cable', 'Cable'),
        ('iptv', 'IPTV'),
        ('ott', 'Over-The-Top'),
    ]
    
    CONTENT_RATING_CHOICES = [
        ('G', 'General Audiences'),
        ('PG', 'Parental Guidance'),
        ('PG13', 'Parents Strongly Cautioned'),
        ('R', 'Restricted'),
        ('NC17', 'Adults Only'),
    ]
    
    name = models.CharField(
        max_length=100, 
        unique=True,
        help_text="Official name of the TV channel"
    )
    slug = models.SlugField(
        max_length=100, 
        unique=True,
        help_text="URL-friendly version of the channel name"
    )
    call_sign = models.CharField(
        max_length=20, 
        unique=True, 
        blank=True,
        help_text="Official call sign or identifier for the channel"
    )
    channel_number = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Channel number for traditional broadcasting"
    )
    channel_type = models.CharField(
        max_length=20, 
        choices=CHANNEL_TYPE_CHOICES,
        help_text="Type of broadcasting technology used"
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the channel and its content"
    )
    logo = models.ImageField(
        upload_to='channels/logos/', 
        blank=True, 
        null=True,
        help_text="Channel logo image"
    )
    website = models.URLField(
        blank=True,
        help_text="Official website URL"
    )
    content_rating = models.CharField(
        max_length=10, 
        choices=CONTENT_RATING_CHOICES, 
        default='G',
        help_text="Content rating for the channel"
    )
    language = models.CharField(
        max_length=10, 
        default='en',
        help_text="Primary language code (ISO 639-1)"
    )
    country = models.CharField(
        max_length=2, 
        blank=True,
        help_text="Country code (ISO 3166-1 alpha-2)"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether the channel is currently active"
    )
    is_hd = models.BooleanField(
        default=False,
        help_text="Whether the channel broadcasts in HD"
    )
    is_4k = models.BooleanField(
        default=False,
        help_text="Whether the channel supports 4K broadcasting"
    )
    launch_date = models.DateField(
        null=True, 
        blank=True,
        help_text="Date when the channel was launched"
    )
    
    # Relationships
    zones = models.ManyToManyField(
        Zone, 
        through='ChannelZone', 
        related_name='channels',
        help_text="Distribution zones where this channel is available"
    )
    
    class Meta:
        db_table = 'channels_channel'
        verbose_name = 'TV Channel'
        verbose_name_plural = 'TV Channels'
        ordering = ['name']
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['channel_type']),
            models.Index(fields=['is_active']),
            models.Index(fields=['country']),
        ]
    
    def __str__(self):
        return self.name
    
    @property
    def active_zones_count(self):
        """
        Return the number of active zones where this channel is distributed.
        """
        return self.channel_zones.filter(is_active=True).count()
    
    @property
    def total_jingles_count(self):
        """
        Return the total number of jingles associated with this channel.
        """
        return self.jingles.count()


class ChannelZone(BaseModel):
    """
    Through model for Channel-Zone relationship with codec configuration.
    
    This model defines how a channel is distributed in a specific zone,
    including the codecs used and technical parameters.
    """
    channel = models.ForeignKey(
        Channel, 
        on_delete=models.CASCADE, 
        related_name='channel_zones',
        help_text="The channel being distributed"
    )
    zone = models.ForeignKey(
        Zone, 
        on_delete=models.CASCADE, 
        related_name='zone_channels',
        help_text="The distribution zone"
    )
    video_codec = models.ForeignKey(
        Codec, 
        on_delete=models.PROTECT, 
        related_name='video_channel_zones',
        limit_choices_to={'codec_type': 'video'},
        help_text="Video codec used for this channel in this zone"
    )
    audio_codec = models.ForeignKey(
        Codec, 
        on_delete=models.PROTECT, 
        related_name='audio_channel_zones',
        limit_choices_to={'codec_type': 'audio'},
        help_text="Audio codec used for this channel in this zone"
    )
    container_format = models.ForeignKey(
        Codec, 
        on_delete=models.PROTECT, 
        related_name='container_channel_zones',
        limit_choices_to={'codec_type': 'container'},
        null=True, 
        blank=True,
        help_text="Container format used for this channel in this zone"
    )
    bitrate = models.PositiveIntegerField(
        help_text="Target bitrate in kbps for this channel in this zone"
    )
    resolution_width = models.PositiveIntegerField(
        default=1920,
        help_text="Video width in pixels"
    )
    resolution_height = models.PositiveIntegerField(
        default=1080,
        help_text="Video height in pixels"
    )
    frame_rate = models.DecimalField(
        max_digits=5, 
        decimal_places=2, 
        default=25.00,
        validators=[MinValueValidator(1.0), MaxValueValidator(120.0)],
        help_text="Frame rate in frames per second"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this channel-zone configuration is active"
    )
    start_date = models.DateTimeField(
        default=timezone.now,
        help_text="When this configuration became active"
    )
    end_date = models.DateTimeField(
        null=True, 
        blank=True,
        help_text="When this configuration will be deactivated (optional)"
    )
    
    class Meta:
        db_table = 'channels_channel_zone'
        unique_together = ['channel', 'zone']
        verbose_name = 'Channel Zone Configuration'
        verbose_name_plural = 'Channel Zone Configurations'
        ordering = ['channel__name', 'zone__name']
        indexes = [
            models.Index(fields=['channel', 'zone']),
            models.Index(fields=['is_active']),
            models.Index(fields=['start_date']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} in {self.zone.name}"
    
    @property
    def resolution_display(self):
        """
        Return a formatted string of the resolution.
        """
        return f"{self.resolution_width}x{self.resolution_height}"
    
    def clean(self):
        """
        Validate that end_date is after start_date if provided.
        """
        from django.core.exceptions import ValidationError
        if self.end_date and self.start_date:
            if self.end_date <= self.start_date:
                raise ValidationError('End date must be after start date.')


class Jingle(BaseModel):
    """
    Model representing jingles used to identify ad break start and end points.
    
    Jingles are audio/video clips that channels use to signal the beginning
    and end of advertisement breaks during live broadcasting.
    """
    JINGLE_TYPE_CHOICES = [
        ('ad_start', 'Ad Break Start'),
        ('ad_end', 'Ad Break End'),
        ('program_start', 'Program Start'),
        ('program_end', 'Program End'),
        ('station_id', 'Station Identification'),
    ]
    
    name = models.CharField(
        max_length=100,
        help_text="Descriptive name for the jingle"
    )
    jingle_type = models.CharField(
        max_length=20, 
        choices=JINGLE_TYPE_CHOICES,
        help_text="Type of jingle and its purpose"
    )
    channel = models.ForeignKey(
        Channel, 
        on_delete=models.CASCADE, 
        related_name='jingles',
        help_text="Channel that uses this jingle"
    )
    audio_file = models.FileField(
        upload_to='channels/jingles/audio/', 
        blank=True, 
        null=True,
        help_text="Audio file for the jingle"
    )
    video_file = models.FileField(
        upload_to='channels/jingles/video/', 
        blank=True, 
        null=True,
        help_text="Video file for the jingle (optional)"
    )
    duration = models.DurationField(
        help_text="Duration of the jingle"
    )
    description = models.TextField(
        blank=True,
        help_text="Additional description or notes about the jingle"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this jingle is currently in use"
    )
    priority = models.PositiveIntegerField(
        default=1,
        validators=[MinValueValidator(1), MaxValueValidator(10)],
        help_text="Priority level (1-10, higher number = higher priority)"
    )
    
    class Meta:
        db_table = 'channels_jingle'
        verbose_name = 'Jingle'
        verbose_name_plural = 'Jingles'
        ordering = ['channel__name', 'jingle_type', '-priority']
        indexes = [
            models.Index(fields=['channel', 'jingle_type']),
            models.Index(fields=['is_active']),
            models.Index(fields=['priority']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.name} ({self.get_jingle_type_display()})"
    
    def clean(self):
        """
        Validate that at least one file (audio or video) is provided.
        """
        from django.core.exceptions import ValidationError
        if not self.audio_file and not self.video_file:
            raise ValidationError('At least one file (audio or video) must be provided.')


class Show(BaseModel):
    """
    Model representing TV shows/programs.
    
    Shows are the content units that make up the EPG (Electronic Program Guide).
    Each show has scheduling information and metadata.
    """
    SHOW_TYPE_CHOICES = [
        ('series', 'TV Series'),
        ('movie', 'Movie'),
        ('news', 'News Program'),
        ('sports', 'Sports'),
        ('documentary', 'Documentary'),
        ('reality', 'Reality Show'),
        ('talk', 'Talk Show'),
        ('variety', 'Variety Show'),
        ('children', 'Children\'s Program'),
        ('educational', 'Educational'),
        ('music', 'Music Program'),
        ('other', 'Other'),
    ]
    
    CONTENT_RATING_CHOICES = [
        ('G', 'General Audiences'),
        ('PG', 'Parental Guidance'),
        ('PG13', 'Parents Strongly Cautioned'),
        ('R', 'Restricted'),
        ('NC17', 'Adults Only'),
    ]
    
    title = models.CharField(
        max_length=200,
        help_text="Title of the show"
    )
    slug = models.SlugField(
        max_length=200, 
        unique=True,
        help_text="URL-friendly version of the show title"
    )
    show_type = models.CharField(
        max_length=20, 
        choices=SHOW_TYPE_CHOICES,
        help_text="Category/type of the show"
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the show"
    )
    short_description = models.CharField(
        max_length=500, 
        blank=True,
        help_text="Brief description for EPG listings"
    )
    poster = models.ImageField(
        upload_to='channels/shows/posters/', 
        blank=True, 
        null=True,
        help_text="Show poster image"
    )
    thumbnail = models.ImageField(
        upload_to='channels/shows/thumbnails/', 
        blank=True, 
        null=True,
        help_text="Thumbnail image for listings"
    )
    content_rating = models.CharField(
        max_length=10, 
        choices=CONTENT_RATING_CHOICES, 
        default='G',
        help_text="Content rating for the show"
    )
    language = models.CharField(
        max_length=10, 
        default='en',
        help_text="Primary language code (ISO 639-1)"
    )
    country = models.CharField(
        max_length=2, 
        blank=True,
        help_text="Country of origin (ISO 3166-1 alpha-2)"
    )
    year = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Year of production/release"
    )
    duration = models.DurationField(
        null=True, 
        blank=True,
        help_text="Typical duration of an episode"
    )
    genre = models.CharField(
        max_length=100, 
        blank=True,
        help_text="Genre tags (comma-separated)"
    )
    cast = models.TextField(
        blank=True,
        help_text="Main cast members"
    )
    director = models.CharField(
        max_length=200, 
        blank=True,
        help_text="Director(s) of the show"
    )
    producer = models.CharField(
        max_length=200, 
        blank=True,
        help_text="Producer(s) of the show"
    )
    imdb_id = models.CharField(
        max_length=20, 
        blank=True,
        help_text="IMDB identifier"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this show is currently active"
    )
    
    class Meta:
        db_table = 'channels_show'
        verbose_name = 'TV Show'
        verbose_name_plural = 'TV Shows'
        ordering = ['title']
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['show_type']),
            models.Index(fields=['is_active']),
            models.Index(fields=['year']),
        ]
    
    def __str__(self):
        return self.title


class EPGEntry(BaseModel):
    """
    Model representing Electronic Program Guide entries.
    
    EPG entries define the schedule of shows for each channel,
    including start/end times and episode-specific information.
    """
    channel = models.ForeignKey(
        Channel, 
        on_delete=models.CASCADE, 
        related_name='epg_entries',
        help_text="Channel broadcasting this program"
    )
    show = models.ForeignKey(
        Show, 
        on_delete=models.CASCADE, 
        related_name='epg_entries',
        help_text="Show being broadcast"
    )
    start_time = models.DateTimeField(
        help_text="Scheduled start time for this program"
    )
    end_time = models.DateTimeField(
        help_text="Scheduled end time for this program"
    )
    episode_title = models.CharField(
        max_length=200, 
        blank=True,
        help_text="Title of the specific episode (if applicable)"
    )
    episode_number = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Episode number within the series"
    )
    season_number = models.PositiveIntegerField(
        null=True, 
        blank=True,
        help_text="Season number (for series)"
    )
    episode_description = models.TextField(
        blank=True,
        help_text="Description specific to this episode"
    )
    is_premiere = models.BooleanField(
        default=False,
        help_text="Whether this is a premiere episode"
    )
    is_finale = models.BooleanField(
        default=False,
        help_text="Whether this is a season/series finale"
    )
    is_repeat = models.BooleanField(
        default=False,
        help_text="Whether this is a repeat broadcast"
    )
    is_live = models.BooleanField(
        default=False,
        help_text="Whether this is a live broadcast"
    )
    audio_language = models.CharField(
        max_length=10, 
        blank=True,
        help_text="Audio language for this broadcast"
    )
    subtitle_language = models.CharField(
        max_length=10, 
        blank=True,
        help_text="Subtitle language (if available)"
    )
    
    class Meta:
        db_table = 'channels_epg_entry'
        verbose_name = 'EPG Entry'
        verbose_name_plural = 'EPG Entries'
        ordering = ['channel__name', 'start_time']
        indexes = [
            models.Index(fields=['channel', 'start_time']),
            models.Index(fields=['start_time', 'end_time']),
            models.Index(fields=['show']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.show.title} ({self.start_time.strftime('%Y-%m-%d %H:%M')})"
    
    @property
    def duration(self):
        """
        Calculate the duration of this EPG entry.
        """
        return self.end_time - self.start_time
    
    @property
    def is_currently_airing(self):
        """
        Check if this program is currently airing.
        """
        now = timezone.now()
        return self.start_time <= now <= self.end_time
    
    def clean(self):
        """
        Validate that end_time is after start_time.
        """
        from django.core.exceptions import ValidationError
        if self.end_time <= self.start_time:
            raise ValidationError('End time must be after start time.')
    
    def save(self, *args, **kwargs):
        """
        Override save to perform validation.
        """
        self.full_clean()
        super().save(*args, **kwargs)