from django import forms
from django.contrib.auth.models import User
from pathlib import Path
from .models import (
    Client, Project, Task, TaskComment,
    DocumentRequest, AssetRequest, CompanyDocument, Role, StaffProfile
)

FORM_ATTRS = {
    'text': {'class': 'staff-input', 'autocomplete': 'off'},
    'textarea': {'class': 'staff-input staff-textarea', 'rows': 3},
    'select': {'class': 'staff-select'},
    'date': {'class': 'staff-input', 'type': 'date'},
    'number': {'class': 'staff-input', 'type': 'number', 'min': '0'},
    'email': {'class': 'staff-input', 'type': 'email'},
    'file': {'class': 'staff-file-input'},
    'checkbox': {'class': 'staff-checkbox'},
}

MAX_UPLOAD_SIZE_BYTES = 10 * 1024 * 1024
DOC_ALLOWED_EXTENSIONS = {'.pdf', '.doc', '.docx', '.png', '.jpg', '.jpeg', '.webp'}
COMMENT_ALLOWED_EXTENSIONS = DOC_ALLOWED_EXTENSIONS | {'.txt', '.csv', '.xlsx', '.zip'}


def _validate_upload(file_obj, *, allowed_extensions, field_label):
    if not file_obj:
        return file_obj
    ext = Path(file_obj.name).suffix.lower()
    if ext not in allowed_extensions:
        raise forms.ValidationError(
            f'{field_label}: unsupported file type "{ext or "unknown"}".'
        )
    if file_obj.size > MAX_UPLOAD_SIZE_BYTES:
        raise forms.ValidationError(
            f'{field_label}: file must be <= {MAX_UPLOAD_SIZE_BYTES // (1024 * 1024)}MB.'
        )
    return file_obj


class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = ['name', 'company_name', 'email', 'phone', 'status', 'notes']
        widgets = {
            'name': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Contact name'}),
            'company_name': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Company name'}),
            'email': forms.EmailInput(attrs={**FORM_ATTRS['email'], 'placeholder': 'client@example.com'}),
            'phone': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': '+1 234 567 8900'}),
            'status': forms.Select(attrs=FORM_ATTRS['select']),
            'notes': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Internal notes about this client...'}),
        }


class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = [
            'client', 'name', 'description', 'start_date', 'end_date',
            'status', 'priority', 'project_manager',
        ]
        widgets = {
            'client': forms.Select(attrs=FORM_ATTRS['select']),
            'name': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Project name'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Project description...'}),
            'start_date': forms.DateInput(attrs=FORM_ATTRS['date']),
            'end_date': forms.DateInput(attrs=FORM_ATTRS['date']),
            'status': forms.Select(attrs=FORM_ATTRS['select']),
            'priority': forms.Select(attrs=FORM_ATTRS['select']),
            'project_manager': forms.Select(attrs=FORM_ATTRS['select']),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['client'].queryset = Client.objects.filter(is_active=True)
        self.fields['project_manager'].queryset = StaffProfile.active_user_queryset()
        self.fields['project_manager'].required = False


class TaskForm(forms.ModelForm):
    assigned_to = forms.ModelMultipleChoiceField(
        queryset=User.objects.none(),
        widget=forms.SelectMultiple(attrs={**FORM_ATTRS['select'], 'size': '4'}),
        required=False,
    )

    class Meta:
        model = Task
        fields = [
            'title', 'description', 'assigned_to', 'start_date', 'due_date',
            'status', 'priority', 'estimated_hours', 'progress_percentage',
        ]
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Task title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Task description...'}),
            'start_date': forms.DateInput(attrs=FORM_ATTRS['date']),
            'due_date': forms.DateInput(attrs=FORM_ATTRS['date']),
            'status': forms.Select(attrs=FORM_ATTRS['select']),
            'priority': forms.Select(attrs=FORM_ATTRS['select']),
            'estimated_hours': forms.NumberInput(attrs={**FORM_ATTRS['number'], 'step': '0.5'}),
            'progress_percentage': forms.NumberInput(attrs={**FORM_ATTRS['number'], 'min': '0', 'max': '100'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['assigned_to'].queryset = StaffProfile.active_user_queryset()


class TaskCommentForm(forms.ModelForm):
    class Meta:
        model = TaskComment
        fields = ['comment', 'attachment']
        widgets = {
            'comment': forms.Textarea(attrs={
                **FORM_ATTRS['textarea'],
                'placeholder': 'Add a comment...',
                'rows': 2,
            }),
            'attachment': forms.FileInput(attrs=FORM_ATTRS['file']),
        }

    def clean_attachment(self):
        return _validate_upload(
            self.cleaned_data.get('attachment'),
            allowed_extensions=COMMENT_ALLOWED_EXTENSIONS,
            field_label='Attachment'
        )


class DocumentRequestForm(forms.ModelForm):
    class Meta:
        model = DocumentRequest
        fields = ['title', 'description', 'preview_text', 'requires_signature', 'deadline', 'file']
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Document title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Internal description...'}),
            'preview_text': forms.Textarea(attrs={
                **FORM_ATTRS['textarea'],
                'placeholder': 'Text the client will see when reviewing this document...',
                'rows': 5
            }),
            'requires_signature': forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
            'deadline': forms.DateInput(attrs=FORM_ATTRS['date']),
            'file': forms.FileInput(attrs=FORM_ATTRS['file']),
        }

    def clean_file(self):
        return _validate_upload(
            self.cleaned_data.get('file'),
            allowed_extensions=DOC_ALLOWED_EXTENSIONS,
            field_label='Document'
        )


class DocumentRequestEditForm(forms.ModelForm):
    class Meta:
        model = DocumentRequest
        fields = ['title', 'description', 'preview_text', 'requires_signature', 'deadline', 'file']
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Document title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Internal description...'}),
            'preview_text': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Text the client will see...', 'rows': 5}),
            'requires_signature': forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
            'deadline': forms.DateInput(attrs=FORM_ATTRS['date']),
            'file': forms.FileInput(attrs=FORM_ATTRS['file']),
        }

    def clean_file(self):
        return _validate_upload(
            self.cleaned_data.get('file'),
            allowed_extensions=DOC_ALLOWED_EXTENSIONS,
            field_label='Document'
        )


class AssetRequestForm(forms.ModelForm):
    class Meta:
        model = AssetRequest
        fields = ['title', 'description', 'required', 'deadline']
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Asset title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Describe what you need from the client...'}),
            'required': forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
            'deadline': forms.DateInput(attrs=FORM_ATTRS['date']),
        }


class AssetRequestEditForm(forms.ModelForm):
    class Meta:
        model = AssetRequest
        fields = ['title', 'description', 'required', 'deadline']
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Asset title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Describe what you need...'}),
            'required': forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
            'deadline': forms.DateInput(attrs=FORM_ATTRS['date']),
        }


class CompanyDocumentForm(forms.ModelForm):
    class Meta:
        model = CompanyDocument
        fields = ['title', 'description', 'file']
        widgets = {
            'title': forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Document title'}),
            'description': forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Internal description...', 'rows': 3}),
            'file': forms.FileInput(attrs=FORM_ATTRS['file']),
        }

    def clean_file(self):
        return _validate_upload(
            self.cleaned_data.get('file'),
            allowed_extensions=COMMENT_ALLOWED_EXTENSIONS,
            field_label='Company document'
        )


class ClientPortalAccountForm(forms.Form):
    """Form for staff to create a client portal login account."""
    email = forms.EmailField(
        widget=forms.EmailInput(attrs={
            **FORM_ATTRS['email'],
            'placeholder': 'client@company.com',
        }),
        help_text="This will be the client's login email"
    )
    first_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'First name'})
    )
    last_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Last name'})
    )
    password = forms.CharField(
        min_length=8,
        widget=forms.PasswordInput(attrs={
            'class': 'staff-input',
            'placeholder': 'Min 8 characters',
            'autocomplete': 'new-password',
        })
    )
    password_confirm = forms.CharField(
        min_length=8,
        widget=forms.PasswordInput(attrs={
            'class': 'staff-input',
            'placeholder': 'Confirm password',
            'autocomplete': 'new-password',
        }),
        label="Confirm Password"
    )
    send_credentials = forms.BooleanField(
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
        label="Show credentials after creation (so you can share them)",
    )

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')
        if password and password_confirm and password != password_confirm:
            self.add_error('password_confirm', 'Passwords do not match.')
        return cleaned_data

    def clean_email(self):
        email = self.cleaned_data['email']
        if User.objects.filter(username=email).exists():
            raise forms.ValidationError('A user with this email already exists.')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('A user with this email already exists.')
        return email


class RoleEditorForm(forms.Form):
    """Create/edit Role with checkbox permissions."""

    name = forms.CharField(
        max_length=100,
        widget=forms.TextInput(attrs={**FORM_ATTRS['text'], 'placeholder': 'Role name'}),
    )
    description = forms.CharField(
        required=False,
        widget=forms.Textarea(attrs={**FORM_ATTRS['textarea'], 'placeholder': 'Role description...'}),
    )

    def __init__(self, *args, **kwargs):
        self.instance = kwargs.pop('instance', None)
        super().__init__(*args, **kwargs)
        self.catalog = Role.get_effective_permission_catalog()
        self._perm_keys = []
        for _, entries in self.catalog.items():
            for key, label in entries:
                self._perm_keys.append(key)
                initial = False
                if self.instance and isinstance(self.instance.permissions, dict):
                    initial = bool(self.instance.permissions.get(key, False))
                self.fields[f'perm_{key}'] = forms.BooleanField(
                    required=False,
                    widget=forms.CheckboxInput(attrs=FORM_ATTRS['checkbox']),
                    initial=initial,
                    label=label,
                )
        if self.instance:
            self.fields['name'].initial = self.instance.name
            self.fields['description'].initial = self.instance.description

    def clean_name(self):
        name = self.cleaned_data['name'].strip()
        if not name:
            raise forms.ValidationError('Role name is required.')
        qs = Role.objects.filter(name__iexact=name, is_active=True)
        if self.instance and self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise forms.ValidationError('A role with this name already exists.')
        return name

    def clean(self):
        cleaned = super().clean()
        perms = {}
        for key in self._perm_keys:
            perms[key] = bool(self.data.get(f'perm_{key}'))
        cleaned['permissions'] = perms
        return cleaned

    def save(self):
        name = self.cleaned_data['name'].strip()
        description = (self.cleaned_data.get('description') or '').strip()
        merged = Role.get_default_permissions().copy()
        if self.instance and self.instance.pk:
            merged.update(self.instance.permissions or {})
        merged.update(self.cleaned_data['permissions'])
        if self.instance:
            self.instance.name = name
            self.instance.description = description
            self.instance.permissions = merged
            self.instance.save()
            return self.instance
        return Role.objects.create(name=name, description=description, permissions=merged)


class UserRoleAssignForm(forms.Form):
    role = forms.ModelChoiceField(
        queryset=Role.objects.none(),
        required=False,
        widget=forms.Select(attrs=FORM_ATTRS['select']),
        label='Role',
    )
    staff_access_active = forms.ChoiceField(
        choices=[
            ('yes', 'Enabled — can use staff login'),
            ('no', 'Disabled — blocked from staff area'),
        ],
        initial='yes',
        widget=forms.RadioSelect,
        label='Staff area access',
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['role'].queryset = Role.objects.filter(is_active=True).order_by('name')
        self.fields['role'].empty_label = '— No role —'
