# -*- coding: utf-8 -*-
"""
Activities Forms

This module defines Django forms for the activities app,
including forms for filtering, searching, and managing
activity logs, audit trails, and security events.

Forms:
    - ActivityFilterForm: Filter activities by various criteria
    - AuditLogFilterForm: Filter audit logs
    - SecurityEventFilterForm: Filter security events
    - ActivityExportForm: Export activities to various formats
    - SecurityEventUpdateForm: Update security event status

Author: AdTlas Development Team
Version: 1.0.0
Last Updated: 2024
"""

from django import forms
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.core.exceptions import ValidationError
from datetime import datetime, timedelta
import json

from .models import Activity, ActivityType, AuditLog, SecurityEvent
from apps.core.forms import BaseForm

User = get_user_model()


class ActivityFilterForm(BaseForm):
    """
    Form for filtering activities by various criteria.
    
    This form provides comprehensive filtering options for
    activity logs including date ranges, users, actions,
    and activity types.
    """
    
    # Date range filters
    date_from = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control',
                'placeholder': 'From date'
            }
        ),
        label='From Date',
        help_text='Filter activities from this date'
    )
    
    date_to = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control',
                'placeholder': 'To date'
            }
        ),
        label='To Date',
        help_text='Filter activities until this date'
    )
    
    # Quick date range options
    QUICK_RANGES = [
        ('', 'All Time'),
        ('today', 'Today'),
        ('yesterday', 'Yesterday'),
        ('last_7_days', 'Last 7 Days'),
        ('last_30_days', 'Last 30 Days'),
        ('last_90_days', 'Last 90 Days'),
        ('this_month', 'This Month'),
        ('last_month', 'Last Month'),
    ]
    
    quick_range = forms.ChoiceField(
        choices=QUICK_RANGES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Quick Range',
        help_text='Select a predefined date range'
    )
    
    # User filter
    user = forms.ModelChoiceField(
        queryset=User.objects.all(),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='User',
        help_text='Filter by specific user'
    )
    
    # Activity type filter
    activity_type = forms.ModelChoiceField(
        queryset=ActivityType.objects.filter(is_active=True),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Activity Type',
        help_text='Filter by activity type'
    )
    
    # Action filter
    action = forms.CharField(
        max_length=100,
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter action name'
            }
        ),
        label='Action',
        help_text='Filter by action name (partial match)'
    )
    
    # Success filter
    SUCCESS_CHOICES = [
        ('', 'All'),
        ('true', 'Successful'),
        ('false', 'Failed'),
    ]
    
    success = forms.ChoiceField(
        choices=SUCCESS_CHOICES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Success Status',
        help_text='Filter by success status'
    )
    
    # Security related filter
    security_related = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Security Related Only',
        help_text='Show only security-related activities'
    )
    
    # IP address filter
    ip_address = forms.GenericIPAddressField(
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter IP address'
            }
        ),
        label='IP Address',
        help_text='Filter by IP address'
    )
    
    # Search query
    search = forms.CharField(
        max_length=255,
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Search in descriptions...'
            }
        ),
        label='Search',
        help_text='Search in activity descriptions'
    )
    
    def clean(self):
        """
        Validate the form data.
        
        Returns:
            dict: Cleaned form data
            
        Raises:
            ValidationError: If validation fails
        """
        cleaned_data = super().clean()
        date_from = cleaned_data.get('date_from')
        date_to = cleaned_data.get('date_to')
        quick_range = cleaned_data.get('quick_range')
        
        # Handle quick range selection
        if quick_range:
            now = timezone.now()
            today = now.replace(hour=0, minute=0, second=0, microsecond=0)
            
            if quick_range == 'today':
                cleaned_data['date_from'] = today
                cleaned_data['date_to'] = today + timedelta(days=1)
            elif quick_range == 'yesterday':
                yesterday = today - timedelta(days=1)
                cleaned_data['date_from'] = yesterday
                cleaned_data['date_to'] = today
            elif quick_range == 'last_7_days':
                cleaned_data['date_from'] = today - timedelta(days=7)
                cleaned_data['date_to'] = now
            elif quick_range == 'last_30_days':
                cleaned_data['date_from'] = today - timedelta(days=30)
                cleaned_data['date_to'] = now
            elif quick_range == 'last_90_days':
                cleaned_data['date_from'] = today - timedelta(days=90)
                cleaned_data['date_to'] = now
            elif quick_range == 'this_month':
                first_day = today.replace(day=1)
                cleaned_data['date_from'] = first_day
                cleaned_data['date_to'] = now
            elif quick_range == 'last_month':
                first_day = today.replace(day=1)
                last_month_end = first_day - timedelta(days=1)
                last_month_start = last_month_end.replace(day=1)
                cleaned_data['date_from'] = last_month_start
                cleaned_data['date_to'] = first_day
        
        # Validate date range
        if date_from and date_to:
            if date_from > date_to:
                raise ValidationError('From date must be before to date.')
            
            # Check if date range is too large (performance consideration)
            if (date_to - date_from).days > 365:
                raise ValidationError('Date range cannot exceed 365 days.')
        
        return cleaned_data
    
    def get_queryset_filters(self):
        """
        Get Django ORM filters based on form data.
        
        Returns:
            dict: Dictionary of ORM filters
        """
        filters = {}
        
        if self.cleaned_data.get('date_from'):
            filters['timestamp__gte'] = self.cleaned_data['date_from']
        
        if self.cleaned_data.get('date_to'):
            filters['timestamp__lte'] = self.cleaned_data['date_to']
        
        if self.cleaned_data.get('user'):
            filters['user'] = self.cleaned_data['user']
        
        if self.cleaned_data.get('activity_type'):
            filters['activity_type'] = self.cleaned_data['activity_type']
        
        if self.cleaned_data.get('action'):
            filters['action__icontains'] = self.cleaned_data['action']
        
        if self.cleaned_data.get('success') == 'true':
            filters['success'] = True
        elif self.cleaned_data.get('success') == 'false':
            filters['success'] = False
        
        if self.cleaned_data.get('security_related'):
            filters['activity_type__is_security_related'] = True
        
        if self.cleaned_data.get('ip_address'):
            filters['ip_address'] = self.cleaned_data['ip_address']
        
        if self.cleaned_data.get('search'):
            filters['description__icontains'] = self.cleaned_data['search']
        
        return filters


class AuditLogFilterForm(BaseForm):
    """
    Form for filtering audit logs.
    
    This form provides filtering options specific to
    audit log entries including model changes and
    administrative actions.
    """
    
    # Date range filters
    date_from = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='From Date'
    )
    
    date_to = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='To Date'
    )
    
    # User filter
    user = forms.ModelChoiceField(
        queryset=User.objects.all(),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='User'
    )
    
    # Action filter
    ACTION_CHOICES = [
        ('', 'All Actions'),
        ('create', 'Create'),
        ('update', 'Update'),
        ('delete', 'Delete'),
    ]
    
    action = forms.ChoiceField(
        choices=ACTION_CHOICES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Action'
    )
    
    # Model filter
    model_name = forms.CharField(
        max_length=100,
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter model name'
            }
        ),
        label='Model Name'
    )
    
    # Object ID filter
    object_id = forms.CharField(
        max_length=255,
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter object ID'
            }
        ),
        label='Object ID'
    )


class SecurityEventFilterForm(BaseForm):
    """
    Form for filtering security events.
    
    This form provides filtering options for security
    events including severity levels and event types.
    """
    
    # Date range filters
    date_from = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='From Date'
    )
    
    date_to = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='To Date'
    )
    
    # Event type filter
    EVENT_TYPE_CHOICES = [
        ('', 'All Types'),
        ('failed_login', 'Failed Login'),
        ('suspicious_activity', 'Suspicious Activity'),
        ('password_change', 'Password Change'),
        ('permission_denied', 'Permission Denied'),
        ('rate_limit_exceeded', 'Rate Limit Exceeded'),
        ('ip_blocked', 'IP Blocked'),
        ('exception', 'Exception'),
    ]
    
    event_type = forms.ChoiceField(
        choices=EVENT_TYPE_CHOICES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Event Type'
    )
    
    # Severity filter
    SEVERITY_CHOICES = [
        ('', 'All Severities'),
        ('low', 'Low'),
        ('medium', 'Medium'),
        ('high', 'High'),
        ('critical', 'Critical'),
    ]
    
    severity = forms.ChoiceField(
        choices=SEVERITY_CHOICES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Severity'
    )
    
    # Status filter
    STATUS_CHOICES = [
        ('', 'All Statuses'),
        ('open', 'Open'),
        ('investigating', 'Investigating'),
        ('resolved', 'Resolved'),
        ('false_positive', 'False Positive'),
    ]
    
    status = forms.ChoiceField(
        choices=STATUS_CHOICES,
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Status'
    )
    
    # User filter
    user = forms.ModelChoiceField(
        queryset=User.objects.all(),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='User'
    )
    
    # IP address filter
    ip_address = forms.GenericIPAddressField(
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter IP address'
            }
        ),
        label='IP Address'
    )


class ActivityExportForm(BaseForm):
    """
    Form for exporting activities to various formats.
    
    This form allows users to export filtered activity
    data in different formats for analysis and reporting.
    """
    
    # Export format
    FORMAT_CHOICES = [
        ('csv', 'CSV'),
        ('json', 'JSON'),
        ('xlsx', 'Excel'),
        ('pdf', 'PDF Report'),
    ]
    
    format = forms.ChoiceField(
        choices=FORMAT_CHOICES,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Export Format',
        help_text='Select the format for export'
    )
    
    # Date range for export
    date_from = forms.DateTimeField(
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='From Date',
        help_text='Start date for export'
    )
    
    date_to = forms.DateTimeField(
        widget=forms.DateTimeInput(
            attrs={
                'type': 'datetime-local',
                'class': 'form-control'
            }
        ),
        label='To Date',
        help_text='End date for export'
    )
    
    # Include options
    include_user_details = forms.BooleanField(
        required=False,
        initial=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Include User Details',
        help_text='Include detailed user information'
    )
    
    include_ip_addresses = forms.BooleanField(
        required=False,
        initial=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Include IP Addresses',
        help_text='Include IP address information'
    )
    
    include_extra_data = forms.BooleanField(
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Include Extra Data',
        help_text='Include additional metadata'
    )
    
    # Security related only
    security_only = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Security Events Only',
        help_text='Export only security-related activities'
    )
    
    def clean(self):
        """
        Validate the export form data.
        
        Returns:
            dict: Cleaned form data
            
        Raises:
            ValidationError: If validation fails
        """
        cleaned_data = super().clean()
        date_from = cleaned_data.get('date_from')
        date_to = cleaned_data.get('date_to')
        
        if date_from and date_to:
            if date_from > date_to:
                raise ValidationError('From date must be before to date.')
            
            # Limit export range for performance
            if (date_to - date_from).days > 90:
                raise ValidationError('Export range cannot exceed 90 days.')
        
        return cleaned_data


class SecurityEventUpdateForm(BaseForm):
    """
    Form for updating security event status and notes.
    
    This form allows security administrators to update
    the status and add investigation notes to security events.
    """
    
    STATUS_CHOICES = [
        ('open', 'Open'),
        ('investigating', 'Investigating'),
        ('resolved', 'Resolved'),
        ('false_positive', 'False Positive'),
    ]
    
    status = forms.ChoiceField(
        choices=STATUS_CHOICES,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Status',
        help_text='Update the investigation status'
    )
    
    notes = forms.CharField(
        widget=forms.Textarea(
            attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': 'Add investigation notes...'
            }
        ),
        label='Investigation Notes',
        help_text='Add notes about the investigation',
        required=False
    )
    
    assigned_to = forms.ModelChoiceField(
        queryset=User.objects.filter(is_staff=True),
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'}),
        label='Assigned To',
        help_text='Assign to a staff member for investigation'
    )
    
    class Meta:
        model = SecurityEvent
        fields = ['status', 'notes', 'assigned_to']


class ActivityTypeForm(BaseForm):
    """
    Form for creating and editing activity types.
    
    This form allows administrators to manage activity
    type configurations including retention policies.
    """
    
    code = forms.CharField(
        max_length=50,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter unique code'
            }
        ),
        label='Code',
        help_text='Unique identifier for this activity type'
    )
    
    name = forms.CharField(
        max_length=100,
        widget=forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter display name'
            }
        ),
        label='Name',
        help_text='Human-readable name for this activity type'
    )
    
    description = forms.CharField(
        widget=forms.Textarea(
            attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': 'Enter description'
            }
        ),
        label='Description',
        help_text='Detailed description of this activity type'
    )
    
    is_security_related = forms.BooleanField(
        required=False,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Security Related',
        help_text='Mark as security-related for special handling'
    )
    
    retention_days = forms.IntegerField(
        min_value=1,
        max_value=3650,  # 10 years
        widget=forms.NumberInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Enter retention period in days'
            }
        ),
        label='Retention Days',
        help_text='Number of days to retain activities of this type'
    )
    
    is_active = forms.BooleanField(
        required=False,
        initial=True,
        widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        label='Active',
        help_text='Whether this activity type is active'
    )
    
    class Meta:
        model = ActivityType
        fields = ['code', 'name', 'description', 'is_security_related', 
                 'retention_days', 'is_active']
    
    def clean_code(self):
        """
        Validate the activity type code.
        
        Returns:
            str: Cleaned code
            
        Raises:
            ValidationError: If code is invalid
        """
        code = self.cleaned_data['code']
        
        # Check for uniqueness (excluding current instance if editing)
        queryset = ActivityType.objects.filter(code=code)
        if self.instance and self.instance.pk:
            queryset = queryset.exclude(pk=self.instance.pk)
        
        if queryset.exists():
            raise ValidationError('Activity type with this code already exists.')
        
        # Validate code format (alphanumeric and underscores only)
        if not code.replace('_', '').isalnum():
            raise ValidationError('Code can only contain letters, numbers, and underscores.')
        
        return code.lower()