"""Channels Models

This module defines the database models for channel management.
It includes models for TV channels, regional zones, codec configurations,
and audio jingles.

Models:
    - Channel: Main TV channel configuration
    - ChannelZone: Regional channel settings and zones
    - ChannelCodec: Video/audio codec configurations
    - Jingle: Audio jingles for channels
    - DayTime: Time slot definitions for programming

The models support:
- Multi-provider configurations (SFR, Bouygues, etc.)
- Regional broadcasting zones
- Codec settings for different quality levels
- Audio jingle management
- Time-based programming slots
"""

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

from apps.core.models import BaseModel, AuditModel, StatusModel
from apps.core.constants import STATUS_CHOICES


User = get_user_model()


class Channel(BaseModel, AuditModel, StatusModel):
    """TV Channel model.
    
    Represents a television channel with its configuration,
    provider settings, and technical specifications.
    
    Attributes:
        name (str): Channel display name
        channel_code (str): Unique channel identifier
        description (str): Channel description
        logo (ImageField): Channel logo
        provider (str): Broadcast provider (SFR, Bouygues, etc.)
        ftp_channel_name (str): FTP directory name for content
        is_hd (bool): Whether channel supports HD
        is_4k (bool): Whether channel supports 4K
        default_codec (str): Default video codec
        audio_codec (str): Default audio codec
        bitrate (int): Default bitrate in kbps
        resolution (str): Default resolution
        frame_rate (float): Default frame rate
        aspect_ratio (str): Default aspect ratio
        language (str): Primary language
        region (str): Broadcasting region
        time_zone (str): Channel timezone
        epg_source (str): EPG data source URL
        is_active (bool): Whether channel is active
    """
    
    # Provider choices
    PROVIDER_CHOICES = [
        ('sfr', 'SFR'),
        ('bouygues', 'Bouygues Telecom'),
        ('orange', 'Orange'),
        ('free', 'Free'),
        ('canal', 'Canal+'),
        ('other', 'Other'),
    ]
    
    # Codec choices
    CODEC_CHOICES = [
        ('h264', 'H.264/AVC'),
        ('h265', 'H.265/HEVC'),
        ('vp9', 'VP9'),
        ('av1', 'AV1'),
    ]
    
    # Audio codec choices
    AUDIO_CODEC_CHOICES = [
        ('aac', 'AAC'),
        ('mp3', 'MP3'),
        ('ac3', 'AC-3'),
        ('eac3', 'E-AC-3'),
        ('opus', 'Opus'),
    ]
    
    # Resolution choices
    RESOLUTION_CHOICES = [
        ('720x576', '720x576 (SD)'),
        ('1280x720', '1280x720 (HD)'),
        ('1920x1080', '1920x1080 (Full HD)'),
        ('3840x2160', '3840x2160 (4K UHD)'),
        ('7680x4320', '7680x4320 (8K UHD)'),
    ]
    
    # Basic Information
    name = models.CharField(
        max_length=200,
        help_text="Channel display name"
    )
    
    channel_code = models.CharField(
        max_length=50,
        unique=True,
        help_text="Unique channel identifier/code"
    )
    
    description = models.TextField(
        blank=True,
        help_text="Channel description and details"
    )
    
    logo = models.ImageField(
        upload_to='channels/logos/',
        blank=True,
        null=True,
        help_text="Channel logo image"
    )
    
    # Provider Configuration
    provider = models.CharField(
        max_length=20,
        choices=PROVIDER_CHOICES,
        default='other',
        help_text="Broadcast provider"
    )
    
    ftp_channel_name = models.CharField(
        max_length=100,
        blank=True,
        help_text="FTP directory name for channel content"
    )
    
    # Technical Specifications
    is_hd = models.BooleanField(
        default=False,
        help_text="Whether channel supports HD broadcasting"
    )
    
    is_4k = models.BooleanField(
        default=False,
        help_text="Whether channel supports 4K broadcasting"
    )
    
    default_codec = models.CharField(
        max_length=20,
        choices=CODEC_CHOICES,
        default='h264',
        help_text="Default video codec for this channel"
    )
    
    audio_codec = models.CharField(
        max_length=20,
        choices=AUDIO_CODEC_CHOICES,
        default='aac',
        help_text="Default audio codec for this channel"
    )
    
    bitrate = models.PositiveIntegerField(
        validators=[MinValueValidator(100), MaxValueValidator(100000)],
        default=2000,
        help_text="Default bitrate in kbps"
    )
    
    resolution = models.CharField(
        max_length=20,
        choices=RESOLUTION_CHOICES,
        default='1920x1080',
        help_text="Default resolution"
    )
    
    frame_rate = models.FloatField(
        validators=[MinValueValidator(1.0), MaxValueValidator(120.0)],
        default=25.0,
        help_text="Default frame rate (fps)"
    )
    
    aspect_ratio = models.CharField(
        max_length=10,
        default='16:9',
        help_text="Default aspect ratio"
    )
    
    # Localization
    language = models.CharField(
        max_length=10,
        default='fr',
        help_text="Primary language code (ISO 639-1)"
    )
    
    region = models.CharField(
        max_length=100,
        blank=True,
        help_text="Broadcasting region or territory"
    )
    
    time_zone = models.CharField(
        max_length=50,
        default='Europe/Paris',
        help_text="Channel timezone"
    )
    
    # EPG Configuration
    epg_source = models.URLField(
        blank=True,
        help_text="EPG (Electronic Program Guide) data source URL"
    )
    
    class Meta:
        verbose_name = _("Channel")
        verbose_name_plural = _("Channels")
        db_table = 'channels_channel'
        ordering = ['name']
        indexes = [
            models.Index(fields=['provider', 'status']),
            models.Index(fields=['channel_code']),
            models.Index(fields=['region', 'status']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.channel_code})"
    
    @property
    def total_jingles(self):
        """Get total number of jingles for this channel."""
        return self.jingles.filter(status='active').count()
    
    @property
    def total_zones(self):
        """Get total number of zones for this channel."""
        return self.zones.filter(status='active').count()
    
    @property
    def codec_configurations(self):
        """Get all codec configurations for this channel."""
        return self.codecs.filter(status='active')
    
    def get_zone_by_region(self, region_name):
        """Get channel zone by region name."""
        return self.zones.filter(region_name=region_name, status='active').first()
    
    def get_codec_by_quality(self, quality):
        """Get codec configuration by quality level."""
        return self.codecs.filter(quality_level=quality, status='active').first()


class ChannelZone(BaseModel, AuditModel, StatusModel):
    """Channel Zone model.
    
    Represents regional zones for channels with specific
    configurations and settings for different geographical areas.
    
    Attributes:
        channel (ForeignKey): Associated channel
        zone_name (str): Zone display name
        region_name (str): Region identifier
        description (str): Zone description
        ftp_path (str): FTP path for this zone
        is_primary (bool): Whether this is the primary zone
        broadcast_start_time (time): Zone broadcast start time
        broadcast_end_time (time): Zone broadcast end time
        time_offset (int): Time offset from UTC in minutes
    """
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='zones',
        help_text="Channel this zone belongs to"
    )
    
    zone_name = models.CharField(
        max_length=100,
        help_text="Zone display name"
    )
    
    region_name = models.CharField(
        max_length=100,
        help_text="Region identifier (e.g., 'paris', 'lyon', 'marseille')"
    )
    
    description = models.TextField(
        blank=True,
        help_text="Zone description and coverage details"
    )
    
    ftp_path = models.CharField(
        max_length=255,
        blank=True,
        help_text="FTP path for zone-specific content"
    )
    
    is_primary = models.BooleanField(
        default=False,
        help_text="Whether this is the primary zone for the channel"
    )
    
    broadcast_start_time = models.TimeField(
        blank=True,
        null=True,
        help_text="Zone broadcast start time"
    )
    
    broadcast_end_time = models.TimeField(
        blank=True,
        null=True,
        help_text="Zone broadcast end time"
    )
    
    time_offset = models.IntegerField(
        default=0,
        help_text="Time offset from UTC in minutes"
    )
    
    class Meta:
        verbose_name = _("Channel Zone")
        verbose_name_plural = _("Channel Zones")
        db_table = 'channels_zone'
        ordering = ['channel__name', 'zone_name']
        unique_together = ['channel', 'region_name']
        indexes = [
            models.Index(fields=['channel', 'is_primary']),
            models.Index(fields=['region_name']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.zone_name}"


class ChannelCodec(BaseModel, AuditModel, StatusModel):
    """Channel Codec Configuration model.
    
    Stores codec configurations for different quality levels
    and technical specifications for each channel.
    
    Attributes:
        channel (ForeignKey): Associated channel
        quality_level (str): Quality level identifier
        video_codec (str): Video codec
        audio_codec (str): Audio codec
        bitrate (int): Bitrate in kbps
        resolution (str): Video resolution
        frame_rate (float): Frame rate
        audio_bitrate (int): Audio bitrate in kbps
        audio_sample_rate (int): Audio sample rate in Hz
        is_default (bool): Whether this is the default codec
    """
    
    QUALITY_CHOICES = [
        ('low', 'Low Quality'),
        ('medium', 'Medium Quality'),
        ('high', 'High Quality'),
        ('ultra', 'Ultra Quality'),
        ('custom', 'Custom'),
    ]
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='codecs',
        help_text="Channel this codec configuration belongs to"
    )
    
    quality_level = models.CharField(
        max_length=20,
        choices=QUALITY_CHOICES,
        help_text="Quality level for this codec configuration"
    )
    
    video_codec = models.CharField(
        max_length=20,
        choices=Channel.CODEC_CHOICES,
        help_text="Video codec"
    )
    
    audio_codec = models.CharField(
        max_length=20,
        choices=Channel.AUDIO_CODEC_CHOICES,
        help_text="Audio codec"
    )
    
    bitrate = models.PositiveIntegerField(
        validators=[MinValueValidator(100), MaxValueValidator(100000)],
        help_text="Video bitrate in kbps"
    )
    
    resolution = models.CharField(
        max_length=20,
        choices=Channel.RESOLUTION_CHOICES,
        help_text="Video resolution"
    )
    
    frame_rate = models.FloatField(
        validators=[MinValueValidator(1.0), MaxValueValidator(120.0)],
        help_text="Frame rate (fps)"
    )
    
    audio_bitrate = models.PositiveIntegerField(
        validators=[MinValueValidator(32), MaxValueValidator(1024)],
        default=128,
        help_text="Audio bitrate in kbps"
    )
    
    audio_sample_rate = models.PositiveIntegerField(
        default=48000,
        help_text="Audio sample rate in Hz"
    )
    
    is_default = models.BooleanField(
        default=False,
        help_text="Whether this is the default codec for the quality level"
    )
    
    class Meta:
        verbose_name = _("Channel Codec")
        verbose_name_plural = _("Channel Codecs")
        db_table = 'channels_codec'
        ordering = ['channel__name', 'quality_level']
        unique_together = ['channel', 'quality_level']
        indexes = [
            models.Index(fields=['channel', 'is_default']),
            models.Index(fields=['quality_level']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.get_quality_level_display()}"


class Jingle(BaseModel, AuditModel, StatusModel):
    """Jingle model.
    
    Represents audio jingles used by channels for branding,
    transitions, and promotional content.
    
    Attributes:
        channel (ForeignKey): Associated channel
        name (str): Jingle name
        description (str): Jingle description
        audio_file (FileField): Audio file
        duration (float): Duration in seconds
        file_size (int): File size in bytes
        audio_format (str): Audio file format
        sample_rate (int): Audio sample rate
        bitrate (int): Audio bitrate
        is_intro (bool): Whether this is an intro jingle
        is_outro (bool): Whether this is an outro jingle
        is_transition (bool): Whether this is a transition jingle
        play_order (int): Play order for sequencing
    """
    
    AUDIO_FORMAT_CHOICES = [
        ('mp3', 'MP3'),
        ('wav', 'WAV'),
        ('aac', 'AAC'),
        ('flac', 'FLAC'),
        ('ogg', 'OGG'),
    ]
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='jingles',
        help_text="Channel this jingle belongs to"
    )
    
    name = models.CharField(
        max_length=200,
        help_text="Jingle name"
    )
    
    description = models.TextField(
        blank=True,
        help_text="Jingle description and usage notes"
    )
    
    audio_file = models.FileField(
        upload_to='channels/jingles/',
        validators=[FileExtensionValidator(allowed_extensions=['mp3', 'wav', 'aac', 'flac', 'ogg'])],
        help_text="Audio file for the jingle"
    )
    
    duration = models.FloatField(
        validators=[MinValueValidator(0.1), MaxValueValidator(300.0)],
        help_text="Duration in seconds"
    )
    
    file_size = models.PositiveIntegerField(
        help_text="File size in bytes"
    )
    
    audio_format = models.CharField(
        max_length=10,
        choices=AUDIO_FORMAT_CHOICES,
        help_text="Audio file format"
    )
    
    sample_rate = models.PositiveIntegerField(
        default=44100,
        help_text="Audio sample rate in Hz"
    )
    
    bitrate = models.PositiveIntegerField(
        validators=[MinValueValidator(32), MaxValueValidator(1024)],
        default=128,
        help_text="Audio bitrate in kbps"
    )
    
    # Jingle Types
    is_intro = models.BooleanField(
        default=False,
        help_text="Whether this is an intro jingle"
    )
    
    is_outro = models.BooleanField(
        default=False,
        help_text="Whether this is an outro jingle"
    )
    
    is_transition = models.BooleanField(
        default=False,
        help_text="Whether this is a transition jingle"
    )
    
    play_order = models.PositiveIntegerField(
        default=0,
        help_text="Play order for sequencing multiple jingles"
    )
    
    class Meta:
        verbose_name = _("Jingle")
        verbose_name_plural = _("Jingles")
        db_table = 'channels_jingle'
        ordering = ['channel__name', 'play_order', 'name']
        indexes = [
            models.Index(fields=['channel', 'status']),
            models.Index(fields=['is_intro', 'is_outro', 'is_transition']),
            models.Index(fields=['play_order']),
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.name}"
    
    @property
    def jingle_type(self):
        """Get the type of jingle as a string."""
        types = []
        if self.is_intro:
            types.append('Intro')
        if self.is_outro:
            types.append('Outro')
        if self.is_transition:
            types.append('Transition')
        return ', '.join(types) if types else 'General'
    
    @property
    def file_size_mb(self):
        """Get file size in megabytes."""
        return round(self.file_size / (1024 * 1024), 2)


class DayTime(BaseModel, AuditModel, StatusModel):
    """Day Time model.
    
    Represents time slots and programming periods for channels.
    Used for scheduling and time-based content management.
    
    Attributes:
        name (str): Time slot name
        description (str): Time slot description
        start_time (time): Start time
        end_time (time): End time
        day_of_week (int): Day of week (0=Monday, 6=Sunday)
        is_prime_time (bool): Whether this is prime time
        is_weekend (bool): Whether this applies to weekends
        priority (int): Priority level for scheduling
    """
    
    DAY_CHOICES = [
        (0, 'Monday'),
        (1, 'Tuesday'),
        (2, 'Wednesday'),
        (3, 'Thursday'),
        (4, 'Friday'),
        (5, 'Saturday'),
        (6, 'Sunday'),
        (7, 'All Days'),
    ]
    
    name = models.CharField(
        max_length=100,
        help_text="Time slot name (e.g., 'Morning', 'Prime Time', 'Late Night')"
    )
    
    description = models.TextField(
        blank=True,
        help_text="Time slot description and characteristics"
    )
    
    start_time = models.TimeField(
        help_text="Start time for this slot"
    )
    
    end_time = models.TimeField(
        help_text="End time for this slot"
    )
    
    day_of_week = models.IntegerField(
        choices=DAY_CHOICES,
        default=7,
        help_text="Day of week (7 = All Days)"
    )
    
    is_prime_time = models.BooleanField(
        default=False,
        help_text="Whether this is considered prime time"
    )
    
    is_weekend = models.BooleanField(
        default=False,
        help_text="Whether this applies specifically to weekends"
    )
    
    priority = models.PositiveIntegerField(
        default=1,
        validators=[MinValueValidator(1), MaxValueValidator(10)],
        help_text="Priority level (1=lowest, 10=highest)"
    )
    
    class Meta:
        verbose_name = _("Day Time Slot")
        verbose_name_plural = _("Day Time Slots")
        db_table = 'channels_daytime'
        ordering = ['day_of_week', 'start_time']
        indexes = [
            models.Index(fields=['day_of_week', 'start_time']),
            models.Index(fields=['is_prime_time']),
            models.Index(fields=['priority']),
        ]
    
    def __str__(self):
        day_name = dict(self.DAY_CHOICES)[self.day_of_week]
        return f"{self.name} ({day_name} {self.start_time}-{self.end_time})"
    
    @property
    def duration_minutes(self):
        """Calculate duration in minutes."""
        start_minutes = self.start_time.hour * 60 + self.start_time.minute
        end_minutes = self.end_time.hour * 60 + self.end_time.minute
        
        # Handle overnight slots
        if end_minutes < start_minutes:
            end_minutes += 24 * 60
        
        return end_minutes - start_minutes
    
    def is_time_in_slot(self, check_time, check_day=None):
        """Check if a given time falls within this slot."""
        if check_day is not None and self.day_of_week != 7 and self.day_of_week != check_day:
            return False
        
        # Handle overnight slots
        if self.end_time < self.start_time:
            return check_time >= self.start_time or check_time <= self.end_time
        else:
            return self.start_time <= check_time <= self.end_time

