from rest_framework import serializers
from django.utils import timezone
from .models import (
    Channel, ChannelZone, ChannelCodec, ChannelZoneRelation,
    EPGProgram, Jingle, JingleDetection, ChannelSchedule
)


class ChannelCodecSerializer(serializers.ModelSerializer):
    """Serializer for channel codec configurations."""
    
    class Meta:
        model = ChannelCodec
        fields = [
            'id', 'name', 'video_codec', 'audio_codec', 
            'resolution', 'bitrate', 'frame_rate', 'ffmpeg_options',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']


class ChannelZoneSerializer(serializers.ModelSerializer):
    """Serializer for channel zones."""
    
    class Meta:
        model = ChannelZone
        fields = [
            'id', 'name', 'code', 'description', 'timezone', 
            'is_active', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']


class ChannelZoneRelationSerializer(serializers.ModelSerializer):
    """Serializer for channel-zone relationships."""
    
    zone = ChannelZoneSerializer(read_only=True)
    codec = ChannelCodecSerializer(read_only=True)
    zone_id = serializers.IntegerField(write_only=True)
    codec_id = serializers.IntegerField(write_only=True, allow_null=True, required=False)
    
    # Connection info as computed field
    connection_info = serializers.SerializerMethodField()
    
    class Meta:
        model = ChannelZoneRelation
        fields = [
            'id', 'zone', 'zone_id', 'codec', 'codec_id',
            'stream_url', 'ftp_host', 'ftp_username', 'ftp_password',
            'ftp_port', 'ftp_root_directory', 'ftp_use_passive',
            'vpn_type', 'vpn_server_address', 'vpn_username', 'vpn_password',
            'ipsec_preshared_key', 'ipsec_local_subnet', 'ipsec_remote_subnet',
            'openvpn_config_file', 'openvpn_ca_cert', 'openvpn_client_cert', 'openvpn_client_key',
            'wireguard_private_key', 'wireguard_public_key', 'wireguard_endpoint', 'wireguard_allowed_ips',
            'is_active', 'priority', 'connection_info',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'connection_info']
        extra_kwargs = {
            'ftp_password': {'write_only': True},
            'vpn_password': {'write_only': True},
            'ipsec_preshared_key': {'write_only': True},
            'openvpn_client_key': {'write_only': True},
            'wireguard_private_key': {'write_only': True},
        }
    
    def get_connection_info(self, obj):
        """Get connection information without sensitive data."""
        return {
            'stream_url': obj.stream_url,
            'ftp': {
                'host': obj.ftp_host,
                'port': obj.ftp_port,
                'root_directory': obj.ftp_root_directory,
                'use_passive': obj.ftp_use_passive,
            },
            'vpn': {
                'type': obj.vpn_type,
                'server_address': obj.vpn_server_address,
            }
        }


class ChannelSerializer(serializers.ModelSerializer):
    """Serializer for TV channels."""
    
    # Zone relationships
    zone_relations = ChannelZoneRelationSerializer(many=True, read_only=True)
    zones = ChannelZoneSerializer(many=True, read_only=True)
    
    # Default codec
    codec = ChannelCodecSerializer(read_only=True)
    codec_id = serializers.IntegerField(write_only=True, allow_null=True, required=False)
    
    # Computed fields
    is_active = serializers.ReadOnlyField()
    current_program = serializers.SerializerMethodField()
    next_program = serializers.SerializerMethodField()
    
    class Meta:
        model = Channel
        fields = [
            'id', 'name', 'display_name', 'channel_number', 'channel_type',
            'status', 'zones', 'zone_relations', 'stream_url', 'backup_stream_url',
            'codec', 'codec_id', 'logo', 'description', 'website',
            'language', 'category', 'target_audience', 'supports_dai',
            'max_ad_duration', 'min_ad_gap', 'last_health_check',
            'is_online', 'is_active', 'current_program', 'next_program',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'is_active', 'current_program', 'next_program',
            'created_at', 'updated_at'
        ]
    
    def get_current_program(self, obj):
        """Get currently airing program."""
        now = timezone.now()
        program = obj.programs.filter(
            start_time__lte=now,
            end_time__gte=now
        ).first()
        return EPGProgramSerializer(program).data if program else None
    
    def get_next_program(self, obj):
        """Get next program to air."""
        now = timezone.now()
        program = obj.programs.filter(
            start_time__gt=now
        ).order_by('start_time').first()
        return EPGProgramSerializer(program).data if program else None


class EPGProgramSerializer(serializers.ModelSerializer):
    """Serializer for EPG program entries."""
    
    channel = serializers.StringRelatedField(read_only=True)
    channel_id = serializers.IntegerField(write_only=True)
    
    # Computed fields
    is_currently_airing = serializers.ReadOnlyField()
    ad_opportunities = serializers.SerializerMethodField()
    
    class Meta:
        model = EPGProgram
        fields = [
            'id', 'channel', 'channel_id', 'title', 'description',
            'program_type', 'start_time', 'end_time', 'duration',
            'season_number', 'episode_number', 'original_air_date',
            'content_rating', 'language', 'subtitles_available',
            'has_ad_breaks', 'ad_break_positions', 'is_currently_airing',
            'ad_opportunities', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'is_currently_airing', 'ad_opportunities',
            'created_at', 'updated_at'
        ]
    
    def get_ad_opportunities(self, obj):
        """Get ad insertion opportunities."""
        return obj.get_ad_opportunities()


class JingleSerializer(serializers.ModelSerializer):
    """Serializer for channel jingles."""
    
    channel = serializers.StringRelatedField(read_only=True)
    channel_id = serializers.IntegerField(write_only=True)
    
    # Computed fields
    can_play_now = serializers.SerializerMethodField()
    
    class Meta:
        model = Jingle
        fields = [
            'id', 'channel', 'channel_id', 'name', 'jingle_type',
            'placement_type', 'file', 'duration', 'audio_fingerprint',
            'video_fingerprint', 'is_active', 'priority', 'start_date',
            'end_date', 'time_slots', 'play_count', 'last_played',
            'can_play_now', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'play_count', 'last_played', 'can_play_now',
            'created_at', 'updated_at'
        ]
    
    def get_can_play_now(self, obj):
        """Check if jingle can be played now."""
        return obj.can_play_now()


class JingleDetectionSerializer(serializers.ModelSerializer):
    """Serializer for jingle detection events."""
    
    channel = serializers.StringRelatedField(read_only=True)
    jingle = serializers.StringRelatedField(read_only=True)
    channel_id = serializers.IntegerField(write_only=True)
    jingle_id = serializers.IntegerField(write_only=True)
    
    # Computed fields
    duration = serializers.ReadOnlyField()
    estimated_ad_break_duration = serializers.SerializerMethodField()
    
    class Meta:
        model = JingleDetection
        fields = [
            'id', 'channel', 'jingle', 'channel_id', 'jingle_id',
            'detected_at', 'start_timestamp', 'end_timestamp',
            'confidence_score', 'detection_method', 'stream_position',
            'status', 'metadata', 'duration', 'estimated_ad_break_duration',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'detected_at', 'duration', 'estimated_ad_break_duration',
            'created_at', 'updated_at'
        ]
    
    def get_estimated_ad_break_duration(self, obj):
        """Get estimated ad break duration."""
        return obj.infer_ad_break_duration()


class ChannelScheduleSerializer(serializers.ModelSerializer):
    """Serializer for channel schedules."""
    
    channel = serializers.StringRelatedField(read_only=True)
    channel_id = serializers.IntegerField(write_only=True)
    
    # Computed fields
    is_currently_active = serializers.ReadOnlyField()
    
    class Meta:
        model = ChannelSchedule
        fields = [
            'id', 'channel', 'channel_id', 'title', 'schedule_type',
            'start_time', 'end_time', 'description', 'content_url',
            'backup_content_url', 'allow_ads', 'ad_break_duration',
            'is_active', 'is_currently_active', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'is_currently_active', 'created_at', 'updated_at'
        ]


class ChannelDetailSerializer(ChannelSerializer):
    """Detailed serializer for individual channel views."""
    
    # Include related data
    jingles = JingleSerializer(many=True, read_only=True)
    schedules = ChannelScheduleSerializer(many=True, read_only=True)
    
    # Recent programs
    recent_programs = serializers.SerializerMethodField()
    upcoming_programs = serializers.SerializerMethodField()
    
    # Recent jingle detections
    recent_jingle_detections = serializers.SerializerMethodField()
    
    class Meta(ChannelSerializer.Meta):
        fields = ChannelSerializer.Meta.fields + [
            'jingles', 'schedules', 'recent_programs', 'upcoming_programs',
            'recent_jingle_detections'
        ]
    
    def get_recent_programs(self, obj):
        """Get recent programs (last 6 hours)."""
        cutoff = timezone.now() - timezone.timedelta(hours=6)
        programs = obj.programs.filter(
            start_time__gte=cutoff
        ).order_by('-start_time')[:10]
        return EPGProgramSerializer(programs, many=True).data
    
    def get_upcoming_programs(self, obj):
        """Get upcoming programs (next 24 hours)."""
        now = timezone.now()
        cutoff = now + timezone.timedelta(hours=24)
        programs = obj.programs.filter(
            start_time__gt=now,
            start_time__lte=cutoff
        ).order_by('start_time')[:10]
        return EPGProgramSerializer(programs, many=True).data
    
    def get_recent_jingle_detections(self, obj):
        """Get recent jingle detections (last 2 hours)."""
        cutoff = timezone.now() - timezone.timedelta(hours=2)
        detections = obj.jingle_detections.filter(
            detected_at__gte=cutoff
        ).order_by('-detected_at')[:20]
        return JingleDetectionSerializer(detections, many=True).data


class ChannelZoneRelationCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating channel-zone relationships."""
    
    class Meta:
        model = ChannelZoneRelation
        fields = [
            'channel', 'zone', 'codec', 'stream_url',
            'ftp_host', 'ftp_username', 'ftp_password', 'ftp_port',
            'ftp_root_directory', 'ftp_use_passive', 'vpn_type',
            'vpn_server_address', 'vpn_username', 'vpn_password',
            'ipsec_preshared_key', 'ipsec_local_subnet', 'ipsec_remote_subnet',
            'openvpn_config_file', 'openvpn_ca_cert', 'openvpn_client_cert',
            'openvpn_client_key', 'wireguard_private_key', 'wireguard_public_key',
            'wireguard_endpoint', 'wireguard_allowed_ips', 'is_active', 'priority'
        ]
        extra_kwargs = {
            'ftp_password': {'write_only': True},
            'vpn_password': {'write_only': True},
            'ipsec_preshared_key': {'write_only': True},
            'openvpn_client_key': {'write_only': True},
            'wireguard_private_key': {'write_only': True},
        }
    
    def validate(self, data):
        """Validate channel-zone relationship data."""
        channel = data.get('channel')
        zone = data.get('zone')
        
        # Check if relationship already exists
        if ChannelZoneRelation.objects.filter(channel=channel, zone=zone).exists():
            raise serializers.ValidationError(
                "Channel-zone relationship already exists."
            )
        
        # Validate VPN configuration based on type
        vpn_type = data.get('vpn_type', 'none')
        if vpn_type == 'ipsec':
            if not data.get('ipsec_preshared_key'):
                raise serializers.ValidationError(
                    "IPSec pre-shared key is required for IPSec VPN."
                )
        elif vpn_type == 'openvpn':
            if not (data.get('openvpn_config_file') or data.get('openvpn_ca_cert')):
                raise serializers.ValidationError(
                    "OpenVPN configuration file or CA certificate is required for OpenVPN."
                )
        elif vpn_type == 'wireguard':
            if not data.get('wireguard_private_key'):
                raise serializers.ValidationError(
                    "WireGuard private key is required for WireGuard VPN."
                )
        
        return data
