# -*- coding: utf-8 -*-
"""
Channel Management Forms

This module contains Django forms for channel management operations including
channel creation, editing, EPG management, and jingle configuration.
"""

import json
from typing import Dict, Any, List

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator, FileExtensionValidator
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model

from .models import (
    Channel, ChannelZone, ChannelCodec, ChannelZoneRelation,
    EPGProgram, Jingle, JingleDetection, ChannelSchedule,
    VPNConfiguration, IPSecConfiguration, OpenVPNConfiguration, WireGuardConfiguration
)

User = get_user_model()


# ============================================================================
# Channel Forms
# ============================================================================

class ChannelForm(forms.ModelForm):
    """
    Form for creating and editing channels.
    """
    
    class Meta:
        model = Channel
        fields = [
            'name', 'description', 'channel_number', 'category', 'language', 'logo', 'status' 
        ]
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Enter channel name')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Enter channel description')
            }),
            'channel_number': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1,
                'max': 9999
            }),
            'category': forms.Select(attrs={'class': 'form-select'}),
            'language': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('e.g., en, fr, es')
            }),
            'country': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('e.g., US, FR, ES')
            }),
            'timezone': forms.Select(attrs={'class': 'form-select'}),
            'logo': forms.FileInput(attrs={
                'class': 'form-control',
                'accept': 'image/*'
            }),
            'stream_url': forms.URLInput(attrs={
                'class': 'form-control',
                'placeholder': _('Primary stream URL')
            }),
            'backup_stream_url': forms.URLInput(attrs={
                'class': 'form-control',
                'placeholder': _('Backup stream URL (optional)')
            }),
            'codec': forms.Select(attrs={'class': 'form-select'}),
            'status': forms.Select(attrs={'class': 'form-select'}),
            'is_hd': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'is_encrypted': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'encryption_key': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Encryption key (if encrypted)')
            }),
            'metadata': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': _('Additional metadata (JSON format)')
            })
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Make certain fields required
        self.fields['name'].required = True
        self.fields['stream_url'].required = True
        self.fields['codec'].required = True
        
        # Set queryset for codec field
        self.fields['codec'].queryset = ChannelCodec.objects.filter(is_active=True)
        
        # Add help text
        self.fields['channel_number'].help_text = _('Unique channel number for EPG')
        self.fields['metadata'].help_text = _('Additional channel metadata in JSON format')
        self.fields['encryption_key'].help_text = _('Required only if channel is encrypted')
    
    def clean_channel_number(self):
        """
        Validate channel number uniqueness.
        """
        channel_number = self.cleaned_data.get('channel_number')
        if channel_number:
            queryset = Channel.objects.filter(channel_number=channel_number)
            if self.instance.pk:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise ValidationError(_('Channel number already exists.'))
        
        return channel_number
    
    def clean_stream_url(self):
        """
        Validate stream URL format.
        """
        stream_url = self.cleaned_data.get('stream_url')
        if stream_url:
            validator = URLValidator()
            try:
                validator(stream_url)
            except ValidationError:
                raise ValidationError(_('Enter a valid stream URL.'))
        
        return stream_url
    
    def clean_metadata(self):
        """
        Validate metadata JSON format.
        """
        metadata = self.cleaned_data.get('metadata')
        if metadata:
            try:
                json.loads(metadata)
            except json.JSONDecodeError:
                raise ValidationError(_('Metadata must be valid JSON.'))
        
        return metadata
    
    def clean(self):
        """
        Perform cross-field validation.
        """
        cleaned_data = super().clean()
        is_encrypted = cleaned_data.get('is_encrypted')
        encryption_key = cleaned_data.get('encryption_key')
        
        # Require encryption key if channel is encrypted
        if is_encrypted and not encryption_key:
            raise ValidationError({
                'encryption_key': _('Encryption key is required for encrypted channels.')
            })
        
        return cleaned_data


class ChannelZoneForm(forms.ModelForm):
    """
    Form for creating and editing channel zones.
    """
    
    class Meta:
        model = ChannelZone
        fields = ['name', 'description', 'timezone', 'is_active']
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Enter zone name')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Enter zone description')
            }),
            'country': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Country code (e.g., US, FR)')
            }),
            'region': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Region or state')
            }),
            'timezone': forms.Select(attrs={'class': 'form-select'}),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
        }
    
    def clean_name(self):
        """
        Validate zone name uniqueness.
        """
        name = self.cleaned_data.get('name')
        if name:
            queryset = ChannelZone.objects.filter(name=name)
            if self.instance.pk:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise ValidationError(_('Zone name already exists.'))
        
        return name


class ChannelCodecForm(forms.ModelForm):
    """
    Form for creating and editing channel codecs.
    """
    
    class Meta:
        model = ChannelCodec
        fields = ['name', 'description', 'codec_type', 'parameters', 'is_active']
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Enter codec name')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Enter codec description')
            }),
            'codec_type': forms.Select(attrs={'class': 'form-select'}),
            'parameters': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': _('Codec parameters (JSON format)')
            }),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
        }
    
    def clean_parameters(self):
        """
        Validate parameters JSON format.
        """
        parameters = self.cleaned_data.get('parameters')
        if parameters:
            try:
                json.loads(parameters)
            except json.JSONDecodeError:
                raise ValidationError(_('Parameters must be valid JSON.'))
        
        return parameters


# ============================================================================
# Channel Zone Relation Forms
# ============================================================================

class ChannelZoneRelationForm(forms.ModelForm):
    """
    Form for creating and editing channel-zone relations.
    """
    
    class Meta:
        model = ChannelZoneRelation
        fields = [
            'channel', 'zone', 'priority', 'is_active',
            'zone_specific_url', 'vpn_type', 'vpn_server',
            'vpn_username', 'vpn_password', 'vpn_config'
        ]
        widgets = {
            'channel': forms.Select(attrs={'class': 'form-select'}),
            'zone': forms.Select(attrs={'class': 'form-select'}),
            'priority': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1,
                'max': 100
            }),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'zone_specific_url': forms.URLInput(attrs={
                'class': 'form-control',
                'placeholder': _('Zone-specific stream URL (optional)')
            }),
            'vpn_type': forms.Select(attrs={'class': 'form-select'}),
            'vpn_server': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('VPN server address')
            }),
            'vpn_username': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('VPN username')
            }),
            'vpn_password': forms.PasswordInput(attrs={
                'class': 'form-control',
                'placeholder': _('VPN password')
            }),
            'vpn_config': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': _('VPN configuration (JSON format)')
            })
        }
    
    def clean_vpn_config(self):
        """
        Validate VPN config JSON format.
        """
        vpn_config = self.cleaned_data.get('vpn_config')
        if vpn_config:
            try:
                json.loads(vpn_config)
            except json.JSONDecodeError:
                raise ValidationError(_('VPN configuration must be valid JSON.'))
        
        return vpn_config
    
    def clean(self):
        """
        Perform cross-field validation for VPN settings.
        """
        cleaned_data = super().clean()
        vpn_type = cleaned_data.get('vpn_type')
        vpn_server = cleaned_data.get('vpn_server')
        vpn_username = cleaned_data.get('vpn_username')
        
        # Require VPN details if VPN type is not 'none'
        if vpn_type and vpn_type != 'none':
            if not vpn_server:
                raise ValidationError({
                    'vpn_server': _('VPN server is required when VPN type is selected.')
                })
            if not vpn_username:
                raise ValidationError({
                    'vpn_username': _('VPN username is required when VPN type is selected.')
                })
        
        return cleaned_data


# ============================================================================
# EPG Forms
# ============================================================================

class EPGProgramForm(forms.ModelForm):
    """
    Form for creating and editing EPG programs.
    """
    
    class Meta:
        model = EPGProgram
        fields = [
            'channel', 'title', 'description', 'category', 'genre',
            'start_time', 'end_time', 'duration', 'rating', 'language',
            'director', 'cast', 'year', 'country', 'episode_number',
            'season_number', 'has_subtitles', 'has_ad_breaks',
            'ad_break_positions', 'metadata'
        ]
        widgets = {
            'channel': forms.Select(attrs={'class': 'form-select'}),
            'title': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Program title')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': _('Program description')
            }),
            'category': forms.Select(attrs={'class': 'form-select'}),
            'genre': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Program genre')
            }),
            'start_time': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'end_time': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'duration': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1,
                'placeholder': _('Duration in minutes')
            }),
            'rating': forms.Select(attrs={'class': 'form-select'}),
            'language': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Program language')
            }),
            'director': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Director name')
            }),
            'cast': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 2,
                'placeholder': _('Cast members (comma-separated)')
            }),
            'year': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1900,
                'max': 2100
            }),
            'country': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Country of origin')
            }),
            'episode_number': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1
            }),
            'season_number': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1
            }),
            'has_subtitles': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'has_ad_breaks': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'ad_break_positions': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 2,
                'placeholder': _('Ad break positions in seconds (JSON array)')
            }),
            'metadata': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Additional metadata (JSON format)')
            })
        }
    
    def clean_ad_break_positions(self):
        """
        Validate ad break positions JSON format.
        """
        ad_break_positions = self.cleaned_data.get('ad_break_positions')
        if ad_break_positions:
            try:
                positions = json.loads(ad_break_positions)
                if not isinstance(positions, list):
                    raise ValidationError(_('Ad break positions must be a JSON array.'))
                
                # Validate that all positions are numbers
                for pos in positions:
                    if not isinstance(pos, (int, float)):
                        raise ValidationError(_('All ad break positions must be numbers.'))
                        
            except json.JSONDecodeError:
                raise ValidationError(_('Ad break positions must be valid JSON.'))
        
        return ad_break_positions
    
    def clean(self):
        """
        Perform cross-field validation.
        """
        cleaned_data = super().clean()
        start_time = cleaned_data.get('start_time')
        end_time = cleaned_data.get('end_time')
        duration = cleaned_data.get('duration')
        
        # Validate time consistency
        if start_time and end_time:
            if end_time <= start_time:
                raise ValidationError({
                    'end_time': _('End time must be after start time.')
                })
            
            # Check duration consistency
            if duration:
                calculated_duration = (end_time - start_time).total_seconds() / 60
                if abs(calculated_duration - duration) > 1:  # Allow 1 minute tolerance
                    raise ValidationError({
                        'duration': _('Duration does not match start and end times.')
                    })
        
        return cleaned_data


# ============================================================================
# Jingle Forms
# ============================================================================

class JingleForm(forms.ModelForm):
    """
    Form for creating and editing jingles.
    """
    
    class Meta:
        model = Jingle
        fields = [
            'channel', 'name', 'description', 'file', 'jingle_type',
            'duration', 'volume_level', 'fade_in', 'fade_out',
            'is_active', 'metadata'
        ]
        widgets = {
            'channel': forms.Select(attrs={'class': 'form-select'}),
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Jingle name')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Jingle description')
            }),
            'file': forms.FileInput(attrs={
                'class': 'form-control',
                'accept': 'audio/*'
            }),
            'jingle_type': forms.Select(attrs={'class': 'form-select'}),
            'duration': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 0.1,
                'step': 0.1,
                'placeholder': _('Duration in seconds')
            }),
            'volume_level': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 0,
                'max': 100,
                'placeholder': _('Volume level (0-100)')
            }),
            'fade_in': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 0,
                'step': 0.1,
                'placeholder': _('Fade in duration (seconds)')
            }),
            'fade_out': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 0,
                'step': 0.1,
                'placeholder': _('Fade out duration (seconds)')
            }),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'metadata': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Additional metadata (JSON format)')
            })
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Add file validation
        self.fields['file'].validators.append(
            FileExtensionValidator(allowed_extensions=['mp3', 'wav', 'aac', 'ogg'])
        )
        
        # Set help text
        self.fields['file'].help_text = _('Supported formats: MP3, WAV, AAC, OGG')
        self.fields['volume_level'].help_text = _('Default volume level for playback')
    
    def clean_metadata(self):
        """
        Validate metadata JSON format.
        """
        metadata = self.cleaned_data.get('metadata')
        if metadata:
            try:
                json.loads(metadata)
            except json.JSONDecodeError:
                raise ValidationError(_('Metadata must be valid JSON.'))
        
        return metadata


# ============================================================================
# Channel Schedule Forms
# ============================================================================

class ChannelScheduleForm(forms.ModelForm):
    """
    Form for creating and editing channel schedules.
    """
    
    class Meta:
        model = ChannelSchedule
        fields = [
            'channel', 'title', 'description', 'schedule_type',
            'start_time', 'end_time', 'is_recurring', 'recurrence_pattern',
            'priority', 'is_active', 'metadata'
        ]
        widgets = {
            'channel': forms.Select(attrs={'class': 'form-select'}),
            'title': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Schedule title')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Schedule description')
            }),
            'schedule_type': forms.Select(attrs={'class': 'form-select'}),
            'start_time': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'end_time': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'is_recurring': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'recurrence_pattern': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Recurrence pattern (e.g., daily, weekly)')
            }),
            'priority': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 1,
                'max': 10
            }),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'metadata': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Additional metadata (JSON format)')
            })
        }
    
    def clean(self):
        """
        Perform cross-field validation.
        """
        cleaned_data = super().clean()
        start_time = cleaned_data.get('start_time')
        end_time = cleaned_data.get('end_time')
        is_recurring = cleaned_data.get('is_recurring')
        recurrence_pattern = cleaned_data.get('recurrence_pattern')
        
        # Validate time consistency
        if start_time and end_time:
            if end_time <= start_time:
                raise ValidationError({
                    'end_time': _('End time must be after start time.')
                })
        
        # Require recurrence pattern for recurring schedules
        if is_recurring and not recurrence_pattern:
            raise ValidationError({
                'recurrence_pattern': _('Recurrence pattern is required for recurring schedules.')
            })
        
        return cleaned_data


# ============================================================================
# Search and Filter Forms
# ============================================================================

class ChannelSearchForm(forms.Form):
    """
    Form for searching and filtering channels.
    """
    
    search = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': _('Search channels...')
        })
    )
    
    category = forms.ChoiceField(
        required=False,
        choices=[('', _('All Categories'))] + Channel.CATEGORY_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    status = forms.ChoiceField(
        required=False,
        choices=[('', _('All Statuses'))] + Channel.STATUS_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    zone = forms.ModelChoiceField(
        required=False,
        queryset=ChannelZone.objects.filter(is_active=True),
        empty_label=_('All Zones'),
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    is_hd = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
    )
    
    is_encrypted = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
    )


class EPGSearchForm(forms.Form):
    """
    Form for searching and filtering EPG programs.
    """
    
    search = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': _('Search programs...')
        })
    )
    
    channel = forms.ModelChoiceField(
        required=False,
        queryset=Channel.objects.filter(status='active'),
        empty_label=_('All Channels'),
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    category = forms.ChoiceField(
        required=False,
        choices=[('', _('All Categories'))] + EPGProgram.CATEGORY_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    date_from = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        })
    )
    
    date_to = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        })
    )
    
    has_subtitles = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
    )
    
    has_ad_breaks = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
    )


# ============================================================================
# Bulk Operation Forms
# ============================================================================

class BulkChannelActionForm(forms.Form):
    """
    Form for bulk operations on channels.
    """
    
    ACTION_CHOICES = [
        ('activate', _('Activate')),
        ('deactivate', _('Deactivate')),
        ('delete', _('Delete')),
        ('export', _('Export')),
        ('health_check', _('Health Check')),
    ]
    
    action = forms.ChoiceField(
        choices=ACTION_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    
    channels = forms.ModelMultipleChoiceField(
        queryset=Channel.objects.all(),
        widget=forms.CheckboxSelectMultiple()
    )
    
    confirm = forms.BooleanField(
        required=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('I confirm this bulk operation')
    )


class ImportChannelsForm(forms.Form):
    """
    Form for importing channels from file.
    """
    
    file = forms.FileField(
        widget=forms.FileInput(attrs={
            'class': 'form-control',
            'accept': '.csv,.json,.xml'
        }),
        validators=[FileExtensionValidator(allowed_extensions=['csv', 'json', 'xml'])],
        help_text=_('Supported formats: CSV, JSON, XML')
    )
    
    update_existing = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('Update existing channels'),
        help_text=_('Update channels if they already exist (based on channel number)')
    )
    
    validate_only = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('Validate only'),
        help_text=_('Only validate the file without importing')
    )