from django import forms
from django.contrib.auth import get_user_model
from django.utils import timezone
from .models import Task, TaskComment, TaskAttachment

User = get_user_model()

class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = [
            'title', 'description', 'due_date', 'priority', 
            'status', 'assigned_to'
        ]
        widgets = {
            'due_date': forms.DateTimeInput(
                attrs={
                    'type': 'datetime-local',
                    'class': 'form-control datetimepicker-input',
                },
                format='%Y-%m-%dT%H:%M'
            ),
            'description': forms.Textarea(attrs={
                'rows': 4,
                'class': 'form-control',
                'placeholder': 'Enter task description...'
            }),
            'title': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Enter task title...'
            }),
            'priority': forms.Select(attrs={
                'class': 'form-select'
            }),
            'status': forms.Select(attrs={
                'class': 'form-select'
            }),
            'assigned_to': forms.Select(attrs={
                'class': 'form-select'
            })
        }
    
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super().__init__(*args, **kwargs)
        
        # Customize the assigned_to field to only show active users
        if 'assigned_to' in self.fields:
            self.fields['assigned_to'].queryset = User.objects.filter(
                is_active=True
            )
            
            # If creating a new task, exclude the current user from assignees
            if not self.instance.pk and self.user:
                self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.exclude(id=self.user.id)
            
            # Make assigned_to field optional
            self.fields['assigned_to'].required = False
        
        # Set current datetime as default for due_date if not set
        if 'due_date' in self.fields and not self.instance.due_date:
            self.fields['due_date'].initial = timezone.now()
    
    def clean_priority(self):
        priority = self.cleaned_data.get('priority')
        if priority and priority not in dict(Task.PRIORITY_CHOICES):
            raise forms.ValidationError('Invalid priority selected.')
        return priority
    
    def clean_status(self):
        status = self.cleaned_data.get('status')
        if status and status not in dict(Task.STATUS_CHOICES):
            raise forms.ValidationError('Invalid status selected.')
        return status
    
    def clean_due_date(self):
        due_date = self.cleaned_data.get('due_date')
        if due_date:
            now = timezone.now()
            if due_date < now:
                raise forms.ValidationError('Due date cannot be in the past.')
            
            # Optional: Add a maximum due date limit (e.g., 1 year from now)
            max_due_date = now + timezone.timedelta(days=365)
            if due_date > max_due_date:
                raise forms.ValidationError('Due date cannot be more than 1 year in the future.')
        return due_date


class TaskCommentForm(forms.ModelForm):
    class Meta:
        model = TaskComment
        fields = ['content']
        widgets = {
            'content': forms.Textarea(attrs={
                'rows': 3,
                'class': 'form-control',
                'placeholder': 'Add a comment...'
            })
        }


class TaskAssignmentForm(forms.Form):
    """Form for assigning tasks to users."""
    task_id = forms.IntegerField(widget=forms.HiddenInput())
    assigned_to = forms.ModelChoiceField(
        queryset=User.objects.none(),
        widget=forms.Select(attrs={'class': 'form-select'}),
        label='Assign To',
        required=True
    )
    
    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super().__init__(*args, **kwargs)
        
        if user and hasattr(user, 'department'):
            # Only show users from the same department
            self.fields['assigned_to'].queryset = User.objects.filter(
                department=user.department,
                is_active=True
            ).exclude(id=user.id)


class TaskAttachmentForm(forms.ModelForm):
    class Meta:
        model = TaskAttachment
        fields = ['file']
        
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.task = kwargs.pop('task', None)
        super().__init__(*args, **kwargs)
        
        self.fields['file'].widget.attrs.update({
            'class': 'form-control',
            'accept': '.pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png,.gif',
            'aria-label': 'Choose file to upload'
        })
    
    def save(self, commit=True):
        attachment = super().save(commit=False)
        if self.user:
            attachment.uploaded_by = self.user
        if self.task:
            attachment.task = self.task
            
        if commit:
            attachment.save()
        return attachment
    
    def clean_file(self):
        file = self.cleaned_data.get('file')
        if file:
            # Limit file size to 10MB
            max_size = 10 * 1024 * 1024  # 10MB
            if file.size > max_size:
                raise forms.ValidationError('File size must be no more than 10MB.')
            
            # Validate file extension
            valid_extensions = [
                '.pdf', '.doc', '.docx', '.xls', '.xlsx', 
                '.jpg', '.jpeg', '.png', '.gif', '.txt'
            ]
            import os
            ext = os.path.splitext(file.name)[1].lower()
            if ext not in valid_extensions:
                raise forms.ValidationError(
                    'Unsupported file type. Please upload one of the following: ' +
                    'PDF, Word, Excel, or image files.'
                )
            
            # Sanitize filename
            filename = os.path.basename(file.name)
            if len(filename) > 100:  # Limit filename length
                name, ext = os.path.splitext(filename)
                filename = name[:95] + ext  # Truncate name if too long
                file.name = filename
                
        return file
