"""
Enterprise-Ready Django Forms

This module provides comprehensive form classes for the common application,
including advanced validation, custom widgets, and enterprise-level features
for data input and validation.

Features:
- Custom form fields with advanced validation
- File upload forms with security checks
- Configuration management forms
- Notification forms with rich text support
- Search and filter forms
- Bulk operation forms
- Import/export forms
- Security-enhanced forms with CSRF protection

Author: Focus Development Team
Version: 2.0.0
License: Proprietary
"""

import json
import mimetypes
from typing import Any, Dict, List, Optional, Union

from django import forms
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import UploadedFile
from django.forms import widgets
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from .models import Configuration, Notification, FileUpload, AuditLog
from .utils import (
    validate_phone_number, validate_password_strength,
    sanitize_html, validate_file_type, calculate_file_hash
)

User = get_user_model()


# ============================================================================
# CUSTOM FORM FIELDS
# ============================================================================

class PhoneNumberField(forms.CharField):
    """Custom field for phone number validation."""
    
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('max_length', 20)
        super().__init__(*args, **kwargs)
    
    def validate(self, value: str) -> None:
        """Validate phone number format."""
        super().validate(value)
        if value and not validate_phone_number(value):
            raise ValidationError(_('Enter a valid phone number.'))


class SecurePasswordField(forms.CharField):
    """Custom field for password with strength validation."""
    
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('widget', forms.PasswordInput(attrs={
            'class': 'form-control',
            'autocomplete': 'new-password'
        }))
        super().__init__(*args, **kwargs)
    
    def validate(self, value: str) -> None:
        """Validate password strength."""
        super().validate(value)
        if value:
            is_valid, feedback = validate_password_strength(value)
            if not is_valid:
                raise ValidationError(feedback)


class RichTextField(forms.CharField):
    """Custom field for rich text with HTML sanitization."""
    
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('widget', forms.Textarea(attrs={
            'class': 'form-control rich-text-editor',
            'rows': 10
        }))
        super().__init__(*args, **kwargs)
    
    def clean(self, value: str) -> str:
        """Clean and sanitize HTML content."""
        value = super().clean(value)
        if value:
            value = sanitize_html(value)
        return value


class SecureFileField(forms.FileField):
    """Custom file field with security validation."""
    
    def __init__(self, allowed_types: Optional[List[str]] = None, 
                 max_size: Optional[int] = None, *args, **kwargs):
        self.allowed_types = allowed_types or []
        self.max_size = max_size or 10 * 1024 * 1024  # 10MB default
        super().__init__(*args, **kwargs)
    
    def validate(self, value: UploadedFile) -> None:
        """Validate file type and size."""
        super().validate(value)
        
        if value:
            # Check file size
            if value.size > self.max_size:
                raise ValidationError(
                    _('File size exceeds maximum allowed size of %(max_size)s bytes.'),
                    params={'max_size': self.max_size}
                )
            
            # Check file type
            if self.allowed_types:
                mime_type, _ = mimetypes.guess_type(value.name)
                if not validate_file_type(value, self.allowed_types):
                    raise ValidationError(
                        _('File type not allowed. Allowed types: %(types)s'),
                        params={'types': ', '.join(self.allowed_types)}
                    )


class JSONField(forms.CharField):
    """Custom field for JSON data validation."""
    
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('widget', forms.Textarea(attrs={
            'class': 'form-control json-editor',
            'rows': 8
        }))
        super().__init__(*args, **kwargs)
    
    def clean(self, value: str) -> Union[Dict, List, None]:
        """Validate and parse JSON data."""
        value = super().clean(value)
        if value:
            try:
                return json.loads(value)
            except json.JSONDecodeError as e:
                raise ValidationError(_('Invalid JSON format: %(error)s'), params={'error': str(e)})
        return None


# ============================================================================
# CUSTOM WIDGETS
# ============================================================================

class DateTimePickerWidget(widgets.DateTimeInput):
    """Custom datetime picker widget."""
    
    def __init__(self, attrs=None, format=None):
        default_attrs = {
            'class': 'form-control datetime-picker',
            'type': 'datetime-local'
        }
        if attrs:
            default_attrs.update(attrs)
        super().__init__(attrs=default_attrs, format=format)


class TagsWidget(widgets.TextInput):
    """Custom widget for tag input."""
    
    def __init__(self, attrs=None):
        default_attrs = {
            'class': 'form-control tags-input',
            'data-role': 'tagsinput'
        }
        if attrs:
            default_attrs.update(attrs)
        super().__init__(attrs=default_attrs)


class ColorPickerWidget(widgets.TextInput):
    """Custom color picker widget."""
    
    def __init__(self, attrs=None):
        default_attrs = {
            'class': 'form-control color-picker',
            'type': 'color'
        }
        if attrs:
            default_attrs.update(attrs)
        super().__init__(attrs=default_attrs)


# ============================================================================
# CONFIGURATION FORMS
# ============================================================================

class ConfigurationForm(forms.ModelForm):
    """Form for managing application configurations."""
    
    class Meta:
        model = Configuration
        fields = ['key', 'value', 'data_type', 'description', 'is_sensitive', 'is_active']
        widgets = {
            'key': forms.TextInput(attrs={'class': 'form-control'}),
            'value': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
            'data_type': forms.Select(attrs={'class': 'form-control'}),
            'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
            'is_sensitive': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        }
    
    def clean_key(self) -> str:
        """Validate configuration key format."""
        key = self.cleaned_data.get('key')
        if key:
            # Check for valid key format (alphanumeric, underscore, dot)
            import re
            if not re.match(r'^[a-zA-Z0-9_.]+$', key):
                raise ValidationError(_('Key must contain only letters, numbers, underscores, and dots.'))
        return key
    
    def clean_value(self) -> str:
        """Validate value based on data type."""
        value = self.cleaned_data.get('value')
        data_type = self.cleaned_data.get('data_type')
        
        if value and data_type:
            try:
                if data_type == 'integer':
                    int(value)
                elif data_type == 'float':
                    float(value)
                elif data_type == 'boolean':
                    if value.lower() not in ['true', 'false', '1', '0']:
                        raise ValueError()
                elif data_type == 'json':
                    json.loads(value)
            except (ValueError, json.JSONDecodeError):
                raise ValidationError(
                    _('Value is not valid for data type %(type)s'),
                    params={'type': data_type}
                )
        
        return value


class BulkConfigurationForm(forms.Form):
    """Form for bulk configuration operations."""
    
    configurations = forms.CharField(
        widget=forms.Textarea(attrs={
            'class': 'form-control',
            'rows': 15,
            'placeholder': 'Enter configurations in JSON format:\n{\n  "key1": "value1",\n  "key2": "value2"\n}'
        }),
        help_text=_('Enter configurations in JSON format')
    )
    
    def clean_configurations(self) -> Dict[str, Any]:
        """Validate and parse configurations JSON."""
        data = self.cleaned_data.get('configurations')
        if data:
            try:
                configs = json.loads(data)
                if not isinstance(configs, dict):
                    raise ValidationError(_('Configurations must be a JSON object.'))
                return configs
            except json.JSONDecodeError as e:
                raise ValidationError(_('Invalid JSON format: %(error)s'), params={'error': str(e)})
        return {}


# ============================================================================
# NOTIFICATION FORMS
# ============================================================================

class NotificationForm(forms.ModelForm):
    """Form for creating and managing notifications."""
    
    message = RichTextField(
        label=_('Message'),
        help_text=_('HTML content is allowed and will be sanitized')
    )
    
    class Meta:
        model = Notification
        fields = [
            'recipient', 'title', 'message', 'notification_type',
            'priority', 'action_url', 'action_text'
        ]
        widgets = {
            'recipient': forms.Select(attrs={'class': 'form-control'}),
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'notification_type': forms.Select(attrs={'class': 'form-control'}),
            'priority': forms.Select(attrs={'class': 'form-control'}),
            'action_url': forms.URLInput(attrs={'class': 'form-control'}),
            'action_text': forms.TextInput(attrs={'class': 'form-control'}),
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['recipient'].queryset = User.objects.filter(is_active=True)


class BulkNotificationForm(forms.Form):
    """Form for sending bulk notifications."""
    
    recipients = forms.ModelMultipleChoiceField(
        queryset=User.objects.filter(is_active=True),
        widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}),
        label=_('Recipients')
    )
    
    title = forms.CharField(
        max_length=200,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('Title')
    )
    
    message = RichTextField(
        label=_('Message'),
        help_text=_('HTML content is allowed and will be sanitized')
    )
    
    notification_type = forms.ChoiceField(
        choices=Notification.NOTIFICATION_TYPES,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Type')
    )
    
    priority = forms.ChoiceField(
        choices=Notification.PRIORITY_CHOICES,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Priority'),
        initial='medium'
    )
    
    send_email = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('Send email notification'),
        help_text=_('Also send notification via email')
    )


# ============================================================================
# FILE UPLOAD FORMS
# ============================================================================

class FileUploadForm(forms.ModelForm):
    """Form for file uploads with security validation."""
    
    file = SecureFileField(
        allowed_types=['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain'],
        max_size=50 * 1024 * 1024,  # 50MB
        label=_('File'),
        help_text=_('Allowed types: JPEG, PNG, GIF, PDF, TXT. Max size: 50MB')
    )
    
    class Meta:
        model = FileUpload
        fields = ['file', 'description']
        widgets = {
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': _('Optional description for the file')
            }),
        }
    
    def save(self, commit=True):
        """Save file upload with additional metadata."""
        instance = super().save(commit=False)
        
        if self.cleaned_data.get('file'):
            file = self.cleaned_data['file']
            instance.original_filename = file.name
            instance.file_size = file.size
            instance.mime_type = file.content_type
            
            # Calculate checksum if file is saved to disk
            if commit:
                instance.save()
                if instance.file and hasattr(instance.file, 'path'):
                    instance.checksum = calculate_file_hash(instance.file.path)
                    instance.save(update_fields=['checksum'])
        
        elif commit:
            instance.save()
        
        return instance


class BulkFileUploadForm(forms.Form):
    """Form for bulk file uploads."""
    
    files = forms.FileField(
        widget=forms.ClearableFileInput(attrs={
            'class': 'form-control',
            'multiple': True
        }),
        label=_('Files'),
        help_text=_('Select multiple files to upload')
    )
    
    description = forms.CharField(
        required=False,
        widget=forms.Textarea(attrs={
            'class': 'form-control',
            'rows': 3,
            'placeholder': _('Optional description for all files')
        }),
        label=_('Description')
    )


# ============================================================================
# SEARCH AND FILTER FORMS
# ============================================================================

class SearchForm(forms.Form):
    """Generic search form."""
    
    query = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': _('Search...'),
            'autocomplete': 'off'
        }),
        label=_('Search Query')
    )
    
    search_type = forms.ChoiceField(
        choices=[
            ('all', _('All Fields')),
            ('title', _('Title')),
            ('content', _('Content')),
            ('user', _('User')),
        ],
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Search In'),
        initial='all'
    )


class DateRangeFilterForm(forms.Form):
    """Form for date range filtering."""
    
    start_date = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        }),
        label=_('Start Date')
    )
    
    end_date = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        }),
        label=_('End Date')
    )
    
    def clean(self) -> Dict[str, Any]:
        """Validate date range."""
        cleaned_data = super().clean()
        start_date = cleaned_data.get('start_date')
        end_date = cleaned_data.get('end_date')
        
        if start_date and end_date and start_date > end_date:
            raise ValidationError(_('Start date must be before end date.'))
        
        return cleaned_data


class AuditLogFilterForm(forms.Form):
    """Form for filtering audit logs."""
    
    user = forms.ModelChoiceField(
        queryset=User.objects.filter(is_active=True),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('User'),
        empty_label=_('All Users')
    )
    
    action = forms.ChoiceField(
        choices=[('', _('All Actions'))] + [
            ('create', _('Create')),
            ('update', _('Update')),
            ('delete', _('Delete')),
            ('login', _('Login')),
            ('logout', _('Logout')),
        ],
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Action')
    )
    
    start_date = forms.DateTimeField(
        required=False,
        widget=DateTimePickerWidget(),
        label=_('Start Date')
    )
    
    end_date = forms.DateTimeField(
        required=False,
        widget=DateTimePickerWidget(),
        label=_('End Date')
    )
    
    ip_address = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': _('IP Address')
        }),
        label=_('IP Address')
    )


# ============================================================================
# IMPORT/EXPORT FORMS
# ============================================================================

class CSVImportForm(forms.Form):
    """Form for CSV data import."""
    
    csv_file = SecureFileField(
        allowed_types=['text/csv', 'application/vnd.ms-excel'],
        max_size=10 * 1024 * 1024,  # 10MB
        label=_('CSV File'),
        help_text=_('Upload a CSV file to import data')
    )
    
    has_header = forms.BooleanField(
        required=False,
        initial=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('File has header row'),
        help_text=_('Check if the first row contains column headers')
    )
    
    update_existing = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('Update existing records'),
        help_text=_('Update records if they already exist')
    )


class DataExportForm(forms.Form):
    """Form for data export configuration."""
    
    export_format = forms.ChoiceField(
        choices=[
            ('csv', _('CSV')),
            ('json', _('JSON')),
            ('xlsx', _('Excel')),
        ],
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Export Format'),
        initial='csv'
    )
    
    date_range = forms.ChoiceField(
        choices=[
            ('all', _('All Time')),
            ('today', _('Today')),
            ('week', _('This Week')),
            ('month', _('This Month')),
            ('year', _('This Year')),
            ('custom', _('Custom Range')),
        ],
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Date Range'),
        initial='all'
    )
    
    start_date = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        }),
        label=_('Start Date')
    )
    
    end_date = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        }),
        label=_('End Date')
    )
    
    include_deleted = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('Include deleted records'),
        help_text=_('Include soft-deleted records in export')
    )


# ============================================================================
# SYSTEM FORMS
# ============================================================================

class SystemMaintenanceForm(forms.Form):
    """Form for system maintenance operations."""
    
    operation = forms.ChoiceField(
        choices=[
            ('cleanup_logs', _('Cleanup Old Logs')),
            ('cleanup_files', _('Cleanup Orphaned Files')),
            ('optimize_db', _('Optimize Database')),
            ('clear_cache', _('Clear Cache')),
            ('backup_data', _('Backup Data')),
        ],
        widget=forms.Select(attrs={'class': 'form-control'}),
        label=_('Operation')
    )
    
    confirm = forms.BooleanField(
        required=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label=_('I understand this operation may affect system performance'),
        help_text=_('Please confirm you understand the implications')
    )


class ContactForm(forms.Form):
    """Generic contact form."""
    
    name = forms.CharField(
        max_length=100,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('Name')
    )
    
    email = forms.EmailField(
        widget=forms.EmailInput(attrs={'class': 'form-control'}),
        label=_('Email')
    )
    
    phone = PhoneNumberField(
        required=False,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('Phone Number')
    )
    
    subject = forms.CharField(
        max_length=200,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('Subject')
    )
    
    message = forms.CharField(
        widget=forms.Textarea(attrs={
            'class': 'form-control',
            'rows': 6
        }),
        label=_('Message')
    )
    
    def send_email(self):
        """Send contact form email."""
        from .utils import send_templated_email
        
        context = {
            'name': self.cleaned_data['name'],
            'email': self.cleaned_data['email'],
            'phone': self.cleaned_data.get('phone', ''),
            'subject': self.cleaned_data['subject'],
            'message': self.cleaned_data['message'],
        }
        
        return send_templated_email(
            template_name='emails/contact_form.html',
            context=context,
            to_emails=['admin@example.com'],
            subject=f"Contact Form: {self.cleaned_data['subject']}"
        )