"""
Channel Audio Management Models

This module contains models for managing channel jingles, station IDs, and audio detection:
- Jingle: Audio content played during broadcasts
- JingleDetection: Detection logs for jingles in live streams

These models handle audio fingerprinting, scheduling, and automatic detection
of jingles in broadcast streams for compliance and monitoring purposes.
"""

from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from apps.common.models import BaseModel
from apps.channels.models.channels import Channel

class Jingle(BaseModel):
    """
    Channel jingles and station IDs with enhanced placement types.
    
    Represents audio content that is played during broadcasts including
    station identifications, bumpers, promos, and transition sounds.
    Supports scheduling, audio fingerprinting, and usage tracking.
    
    Attributes:
        channel: Foreign key to the channel this jingle belongs to
        name: Human-readable name for the jingle
        jingle_type: Type of jingle (station_id, bumper, promo, etc.)
        placement_type: When the jingle should be played in the broadcast
        file: Audio file for the jingle
        duration: Length of the jingle in seconds
        audio_fingerprint: Audio fingerprint data for automatic detection
        video_fingerprint: Video fingerprint data for automatic detection
        is_active: Whether this jingle is currently active
        priority: Priority level for jingle selection
        start_date: Optional start date for jingle validity
        end_date: Optional end date for jingle validity
        time_slots: JSON field with time ranges when jingle can play
        play_count: Number of times this jingle has been played
        last_played: Timestamp of last play
    
    Related Models:
        - Channel: One-to-many relationship (channel can have multiple jingles)
        - JingleDetection: One-to-many relationship (jingle can have multiple detections)
    """
    
    JINGLE_TYPES = [
        ("station_id", _("Station ID")),
        ("bumper", _("Bumper")),
        ("promo", _("Promo")),
        ("transition", _("Transition")),
        ("commercial_break", _("Commercial Break")),
    ]
    
    PLACEMENT_TYPES = [
        ("start", _("Start of Show")),
        ("end", _("End of Show")),
        ("commercial_start", _("Start of Commercial Break")),
        ("commercial_end", _("End of Commercial Break")),
        ("program_transition", _("Program Transition")),
        ("hourly", _("Hourly")),
        ("half_hourly", _("Half Hourly")),
        ("random", _("Random Placement")),
    ]
    
    # Relationships
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name="jingles",
        verbose_name=_("Channel"),
        help_text=_("Channel this jingle belongs to")
    )
    
    # Basic Information
    name = models.CharField(
        max_length=255,
        verbose_name=_("Jingle Name"),
        help_text=_("Human-readable name for this jingle")
    )
    jingle_type = models.CharField(
        max_length=20,
        choices=JINGLE_TYPES,
        verbose_name=_("Jingle Type"),
        help_text=_("Type of jingle content")
    )
    placement_type = models.CharField(
        max_length=20, 
        choices=PLACEMENT_TYPES,
        default="random",
        verbose_name=_("Placement Type"),
        help_text=_("When this jingle should be played in the broadcast")
    )
    
    # Media Files
    file = models.FileField(
        upload_to="jingles/",
        verbose_name=_("Audio File"),
        help_text=_("Audio file for this jingle")
    )
    duration = models.PositiveIntegerField(
        verbose_name=_("Duration"),
        help_text=_("Duration of the jingle in seconds")
    )
    
    # Audio/Video Fingerprinting
    audio_fingerprint = models.TextField(
        blank=True,
        verbose_name=_("Audio Fingerprint"),
        help_text=_("Audio fingerprint data for automatic detection in streams")
    )
    video_fingerprint = models.TextField(
        blank=True,
        verbose_name=_("Video Fingerprint"),
        help_text=_("Video fingerprint data for automatic detection in streams")
    )
    
    # Usage Settings
    is_active = models.BooleanField(
        default=True,
        verbose_name=_("Is Active"),
        help_text=_("Whether this jingle is currently active")
    )
    priority = models.PositiveIntegerField(
        default=1,
        verbose_name=_("Priority"),
        help_text=_("Priority level for jingle selection (higher number = higher priority)")
    )
    
    # Scheduling
    start_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Start Date"),
        help_text=_("Optional start date for when this jingle becomes active")
    )
    end_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("End Date"),
        help_text=_("Optional end date for when this jingle becomes inactive")
    )
    time_slots = models.JSONField(
        default=list,
        blank=True,
        verbose_name=_("Time Slots"),
        help_text=_("JSON list of time ranges when this jingle can play")
    )
    
    # Usage Tracking
    play_count = models.PositiveIntegerField(
        default=0,
        verbose_name=_("Play Count"),
        help_text=_("Number of times this jingle has been played")
    )
    last_played = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_("Last Played"),
        help_text=_("Timestamp of when this jingle was last played")
    )
    
    class Meta:
        db_table = "jingles"
        ordering = ["channel", "-priority", "name"]
        verbose_name = _("Jingle")
        verbose_name_plural = _("Jingles")
        indexes = [
            models.Index(fields=["channel", "is_active"]),
            models.Index(fields=["placement_type", "is_active"]),
            models.Index(fields=["priority", "is_active"]),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.channel.name})"
    
    def can_play_now(self):
        """
        Check if jingle can be played at the current time.
        
        Returns:
            bool: True if jingle can be played now, False otherwise
            
        Checks:
            - Jingle is active
            - Current date is within start/end date range
            - Current time is within allowed time slots
        """
        if not self.is_active:
            return False
        
        now = timezone.now()
        
        # Check date range
        if self.start_date and now.date() < self.start_date:
            return False
        if self.end_date and now.date() > self.end_date:
            return False
        
        # Check time slots
        if self.time_slots:
            current_time = now.time()
            for slot in self.time_slots:
                try:
                    start_time = timezone.datetime.strptime(slot["start"], "%H:%M").time()
                    end_time = timezone.datetime.strptime(slot["end"], "%H:%M").time()
                    if start_time <= current_time <= end_time:
                        return True
                except (KeyError, ValueError):
                    continue
            return False
        
        return True
    
    def mark_played(self):
        """
        Mark jingle as played and update usage statistics.
        
        Updates:
            - Increments play_count
            - Sets last_played to current timestamp
        """
        self.play_count += 1
        self.last_played = timezone.now()
        self.save(update_fields=["play_count", "last_played"])
    
    def get_usage_stats(self):
        """
        Get usage statistics for this jingle.
        
        Returns:
            dict: Dictionary containing usage statistics
        """
        return {
            'play_count': self.play_count,
            'last_played': self.last_played,
            'is_active': self.is_active,
            'can_play_now': self.can_play_now(),
        }


class JingleDetection(BaseModel):
    """
    Log of detected jingles in live streams.
    
    Records when jingles are automatically detected in broadcast streams
    using audio/video fingerprinting. Used for compliance monitoring,
    ad break detection, and broadcast analysis.
    
    Attributes:
        channel: Foreign key to the channel where detection occurred
        jingle: Foreign key to the detected jingle
        detected_at: Timestamp when detection was recorded
        start_timestamp: When the jingle started playing in the stream
        end_timestamp: When the jingle ended playing in the stream
        confidence_score: Detection confidence from 0.0 to 1.0
        detection_method: Method used for detection
        stream_position: Position in stream where jingle was detected
        status: Validation status of the detection
        metadata: Additional detection metadata
    
    Related Models:
        - Channel: Many-to-one relationship
        - Jingle: Many-to-one relationship
    """
    
    DETECTION_STATUS = [
        ("detected", _("Detected")),
        ("confirmed", _("Confirmed")),
        ("false_positive", _("False Positive")),
    ]
    
    DETECTION_METHODS = [
        ("audio_fingerprint", _("Audio Fingerprint")),
        ("video_fingerprint", _("Video Fingerprint")),
        ("combined", _("Combined Audio/Video")),
        ("manual", _("Manual Detection")),
    ]
    
    # Relationships
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name="jingle_detections",
        verbose_name=_("Channel"),
        help_text=_("Channel where the jingle was detected")
    )
    jingle = models.ForeignKey(
        Jingle,
        on_delete=models.CASCADE,
        related_name="detections",
        verbose_name=_("Jingle"),
        help_text=_("The jingle that was detected")
    )
    
    # Detection Timestamps
    detected_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Detected At"),
        help_text=_("When the detection was recorded in the system")
    )
    start_timestamp = models.DateTimeField(
        verbose_name=_("Start Time"),
        help_text=_("When the jingle started playing in the stream")
    )
    end_timestamp = models.DateTimeField(
        verbose_name=_("End Time"),
        help_text=_("When the jingle ended playing in the stream")
    )
    
    # Detection Quality and Method
    confidence_score = models.DecimalField(
        max_digits=5, 
        decimal_places=4,
        verbose_name=_("Confidence Score"),
        help_text=_("Detection confidence score from 0.0 to 1.0")
    )
    detection_method = models.CharField(
        max_length=50,
        choices=DETECTION_METHODS,
        default="audio_fingerprint",
        verbose_name=_("Detection Method"),
        help_text=_("Method used for detection")
    )
    
    # Stream Context
    stream_position = models.PositiveIntegerField(
        verbose_name=_("Stream Position"),
        help_text=_("Position in stream where jingle was detected (seconds from start)")
    )
    
    # Validation and Status
    status = models.CharField(
        max_length=20,
        choices=DETECTION_STATUS,
        default="detected",
        verbose_name=_("Status"),
        help_text=_("Validation status of this detection")
    )
    
    # Additional Data
    metadata = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_("Metadata"),
        help_text=_("Additional detection metadata and parameters")
    )
    
    class Meta:
        db_table = "jingle_detections"
        ordering = ["-detected_at"]
        verbose_name = _("Jingle Detection")
        verbose_name_plural = _("Jingle Detections")
        indexes = [
            models.Index(fields=["channel", "detected_at"]),
            models.Index(fields=["jingle", "detected_at"]),
            models.Index(fields=["start_timestamp", "end_timestamp"]),
            models.Index(fields=["status", "detected_at"]),
            models.Index(fields=["confidence_score"]),
        ]
    
    def __str__(self):
        return f"{self.jingle.name} detected on {self.channel.name} at {self.start_timestamp}"
    
    @property
    def duration(self):
        """
        Get detection duration in seconds.
        
        Returns:
            float: Duration of the detected jingle in seconds
        """
        if self.start_timestamp and self.end_timestamp:
            return (self.end_timestamp - self.start_timestamp).total_seconds()
        return 0
    
    @property
    def is_confirmed(self):
        """Check if detection has been confirmed."""
        return self.status == "confirmed"
    
    @property
    def is_false_positive(self):
        """Check if detection is marked as false positive."""
        return self.status == "false_positive"
    
    def infer_ad_break_duration(self):
        """
        Infer ad break duration based on jingle placement.
        
        For jingles that mark the start of commercial breaks, attempts to
        find the corresponding end-of-break jingle to calculate the actual
        ad break duration.
        
        Returns:
            int: Estimated ad break duration in seconds
        """
        if self.jingle.placement_type == "commercial_start":
            # Look for the corresponding commercial_end jingle
            try:
                end_detection = JingleDetection.objects.filter(
                    channel=self.channel,
                    jingle__placement_type="commercial_end",
                    start_timestamp__gt=self.start_timestamp,
                    start_timestamp__lt=self.start_timestamp + timezone.timedelta(minutes=10),
                    status__in=["detected", "confirmed"]
                ).first()
                
                if end_detection:
                    return (end_detection.start_timestamp - self.end_timestamp).total_seconds()
            except JingleDetection.DoesNotExist:
                pass
        
        # Fallback to channel's default ad break duration
        return self.channel.max_ad_duration
    
    def confirm_detection(self, confirmed_by=None):
        """
        Mark detection as confirmed.
        
        Args:
            confirmed_by: Optional user who confirmed the detection
        """
        self.status = "confirmed"
        if confirmed_by:
            if 'confirmed_by' not in self.metadata:
                self.metadata['confirmed_by'] = str(confirmed_by)
            self.metadata['confirmed_at'] = timezone.now().isoformat()
        self.save(update_fields=["status", "metadata"])
    
    def mark_false_positive(self, marked_by=None):
        """
        Mark detection as false positive.
        
        Args:
            marked_by: Optional user who marked this as false positive
        """
        self.status = "false_positive"
        if marked_by:
            if 'marked_by' not in self.metadata:
                self.metadata['marked_by'] = str(marked_by)
            self.metadata['marked_false_positive_at'] = timezone.now().isoformat()
        self.save(update_fields=["status", "metadata"])
    
    def get_detection_summary(self):
        """
        Get a summary of this detection.
        
        Returns:
            dict: Summary information about the detection
        """
        return {
            'jingle_name': self.jingle.name,
            'channel_name': self.channel.name,
            'duration': self.duration,
            'confidence': float(self.confidence_score),
            'method': self.detection_method,
            'status': self.status,
            'detected_at': self.detected_at,
            'stream_position': self.stream_position,
        }