import re

from django import forms
from django.core.exceptions import ValidationError

from ..models import Person


class UserCreationForm(forms.Form):
    """Form für die Erstellung neuer Benutzer"""

    username = forms.CharField(
        label="Benutzername",
        max_length=150,
        help_text="Eindeutiger Benutzername für die Anmeldung",
        widget=forms.TextInput(attrs={"class": "form-control"}),
    )

    email = forms.EmailField(
        label="E-Mail-Adresse",
        help_text="E-Mail-Adresse des Benutzers",
        widget=forms.EmailInput(attrs={"class": "form-control"}),
    )

    first_name = forms.CharField(
        label="Vorname",
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"class": "form-control"}),
    )

    last_name = forms.CharField(
        label="Nachname",
        max_length=150,
        required=False,
        widget=forms.TextInput(attrs={"class": "form-control"}),
    )

    password1 = forms.CharField(
        label="Passwort",
        widget=forms.PasswordInput(attrs={"class": "form-control"}),
        help_text="Mindestens 8 Zeichen",
    )

    password2 = forms.CharField(
        label="Passwort bestätigen",
        widget=forms.PasswordInput(attrs={"class": "form-control"}),
        help_text="Geben Sie das Passwort zur Bestätigung erneut ein",
    )

    is_active = forms.BooleanField(
        label="Aktiv",
        required=False,
        initial=True,
        help_text="Benutzer kann sich anmelden",
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
    )

    is_staff = forms.BooleanField(
        label="Staff-Status",
        required=False,
        help_text="Benutzer kann auf Django Admin zugreifen",
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
    )

    def clean_username(self):
        username = self.cleaned_data["username"]
        from django.contrib.auth.models import User

        if User.objects.filter(username=username).exists():
            raise forms.ValidationError(
                "Ein Benutzer mit diesem Namen existiert bereits."
            )
        return username

    def clean_email(self):
        email = self.cleaned_data["email"]
        from django.contrib.auth.models import User

        if User.objects.filter(email=email).exists():
            raise forms.ValidationError(
                "Ein Benutzer mit dieser E-Mail-Adresse existiert bereits."
            )
        return email

    def clean(self):
        cleaned_data = super().clean()
        password1 = cleaned_data.get("password1")
        password2 = cleaned_data.get("password2")

        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError("Die Passwörter stimmen nicht überein.")
            if len(password1) < 8:
                raise forms.ValidationError(
                    "Das Passwort muss mindestens 8 Zeichen lang sein."
                )

        return cleaned_data


class UserUpdateForm(forms.ModelForm):
    """Form für die Bearbeitung bestehender Benutzer"""

    class Meta:
        from django.contrib.auth.models import User

        model = User
        fields = [
            "username",
            "email",
            "first_name",
            "last_name",
            "is_active",
            "is_staff",
        ]
        widgets = {
            "username": forms.TextInput(attrs={"class": "form-control"}),
            "email": forms.EmailInput(attrs={"class": "form-control"}),
            "first_name": forms.TextInput(attrs={"class": "form-control"}),
            "last_name": forms.TextInput(attrs={"class": "form-control"}),
            "is_active": forms.CheckboxInput(attrs={"class": "form-check-input"}),
            "is_staff": forms.CheckboxInput(attrs={"class": "form-check-input"}),
        }
        labels = {
            "username": "Benutzername",
            "email": "E-Mail-Adresse",
            "first_name": "Vorname",
            "last_name": "Nachname",
            "is_active": "Aktiv",
            "is_staff": "Staff-Status",
        }
        help_texts = {
            "username": "Eindeutiger Benutzername für die Anmeldung",
            "email": "E-Mail-Adresse des Benutzers",
            "is_active": "Benutzer kann sich anmelden",
            "is_staff": "Benutzer kann auf Django Admin zugreifen",
        }


class PasswordChangeForm(forms.Form):
    """Form für Passwort-Änderungen"""

    new_password1 = forms.CharField(
        label="Neues Passwort",
        widget=forms.PasswordInput(attrs={"class": "form-control"}),
        help_text="Mindestens 8 Zeichen",
    )

    new_password2 = forms.CharField(
        label="Neues Passwort bestätigen",
        widget=forms.PasswordInput(attrs={"class": "form-control"}),
        help_text="Geben Sie das neue Passwort zur Bestätigung erneut ein",
    )

    def clean(self):
        cleaned_data = super().clean()
        password1 = cleaned_data.get("new_password1")
        password2 = cleaned_data.get("new_password2")

        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError("Die Passwörter stimmen nicht überein.")
            if len(password1) < 8:
                raise forms.ValidationError(
                    "Das Passwort muss mindestens 8 Zeichen lang sein."
                )

        return cleaned_data


class UserPermissionForm(forms.Form):
    """Form für die Zuweisung von Berechtigungen"""

    def __init__(self, *args, **kwargs):
        user = kwargs.pop("user", None)
        super().__init__(*args, **kwargs)

        from django.contrib.auth.models import Permission

        # Get all custom permissions for stiftung app
        app_permissions = Permission.objects.filter(
            content_type__app_label="stiftung"
        ).order_by("name")

        # Create checkbox fields for each permission
        for perm in app_permissions:
            field_name = f"perm_{perm.id}"
            self.fields[field_name] = forms.BooleanField(
                label=perm.name,
                required=False,
                widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
            )

            # Set initial values if user is provided
            if user:
                self.fields[field_name].initial = user.has_perm(
                    f"stiftung.{perm.codename}"
                )

    def get_permission_groups(self):
        """Group permissions by functionality for template rendering"""
        from django.contrib.auth.models import Permission

        groups = {
            "entities": {
                "name": "Entitäten verwalten",
                "permissions": [],
                "icon": "fas fa-users",
            },
            "documents": {
                "name": "Dokumentenverwaltung",
                "permissions": [],
                "icon": "fas fa-folder-open",
            },
            "financial": {
                "name": "Finanzverwaltung",
                "permissions": [],
                "icon": "fas fa-euro-sign",
            },
            "administration": {
                "name": "Administration",
                "permissions": [],
                "icon": "fas fa-cogs",
            },
            "system": {"name": "System", "permissions": [], "icon": "fas fa-server"},
        }

        # Get all permissions to properly categorize them
        for field_name, field in self.fields.items():
            if field_name.startswith("perm_"):
                # Extract permission ID from field name
                perm_id = field_name.replace("perm_", "")
                try:
                    permission = Permission.objects.get(id=perm_id)
                    label = permission.name.lower()
                    codename = permission.codename.lower()

                    # Get bound field for proper template rendering
                    bound_field = self[field_name]

                    # More precise categorization based on both name and codename
                    if (
                        any(
                            word in codename
                            for word in [
                                "destinataer",
                                "land",
                                "paechter",
                                "verpachtung",
                                "foerderung",
                            ]
                        )
                        and "manage_" in codename
                        or "view_" in codename
                    ):
                        groups["entities"]["permissions"].append(
                            (field_name, bound_field, permission)
                        )
                    elif (
                        any(
                            word in codename for word in ["documents", "link_documents"]
                        )
                        or "dokument" in label
                    ):
                        groups["documents"]["permissions"].append(
                            (field_name, bound_field, permission)
                        )
                    elif any(
                        word in codename
                        for word in [
                            "verwaltungskosten",
                            "konten",
                            "rentmeister",
                            "approve_payments",
                        ]
                    ) or any(
                        word in label
                        for word in [
                            "verwaltungskosten",
                            "konto",
                            "rentmeister",
                            "zahlung",
                        ]
                    ):
                        groups["financial"]["permissions"].append(
                            (field_name, bound_field, permission)
                        )
                    elif any(
                        word in codename
                        for word in [
                            "administration",
                            "audit",
                            "backup",
                            "manage_users",
                            "manage_permissions",
                        ]
                    ) or any(
                        word in label
                        for word in [
                            "administration",
                            "audit",
                            "backup",
                            "benutzer",
                            "berechtigung",
                        ]
                    ):
                        groups["administration"]["permissions"].append(
                            (field_name, bound_field, permission)
                        )
                    else:
                        groups["system"]["permissions"].append(
                            (field_name, bound_field, permission)
                        )
                except Permission.DoesNotExist:
                    # Create a fallback permission-like object with proper display
                    class FallbackPermission:
                        def __init__(self, field_name):
                            self.name = field_name.replace('_', ' ').title()
                            self.codename = field_name

                    fallback_perm = FallbackPermission(field_name)
                    bound_field = self[field_name]  # Get bound field for exception case too
                    groups["system"]["permissions"].append((field_name, bound_field, fallback_perm))

        return groups


class TwoFactorSetupForm(forms.Form):
    """Form for setting up 2FA with TOTP verification"""
    token = forms.CharField(
        max_length=6,
        min_length=6,
        widget=forms.TextInput(attrs={
            'class': 'form-control text-center',
            'placeholder': '000000',
            'autocomplete': 'off',
            'pattern': '[0-9]{6}',
            'inputmode': 'numeric'
        }),
        label='Bestätigungscode',
        help_text='6-stelliger Code aus Ihrer Authenticator-App'
    )

    def clean_token(self):
        token = self.cleaned_data.get('token')
        if token and not token.isdigit():
            raise ValidationError('Der Code darf nur Zahlen enthalten.')
        return token


class TwoFactorVerifyForm(forms.Form):
    """Form for verifying 2FA during login"""
    otp_token = forms.CharField(
        max_length=8,
        min_length=6,
        widget=forms.TextInput(attrs={
            'class': 'form-control form-control-lg text-center',
            'placeholder': '000000',
            'autocomplete': 'off',
            'autofocus': True
        }),
        label='Authentifizierungscode',
        help_text='6-stelliger Code aus der App oder 8-stelliger Backup-Code'
    )

    def clean_otp_token(self):
        token = self.cleaned_data.get('otp_token')
        if token:
            token = token.strip().lower()
            # Allow 6-digit TOTP codes or 8-character backup codes
            if len(token) == 6 and token.isdigit():
                return token
            elif len(token) == 8 and re.match(r'^[a-f0-9]{8}$', token):
                return token
            else:
                raise ValidationError(
                    'Bitte geben Sie einen 6-stelligen Authenticator-Code oder 8-stelligen Backup-Code ein.'
                )
        return token


class TwoFactorDisableForm(forms.Form):
    """Form for disabling 2FA with password confirmation"""
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'autocomplete': 'current-password',
            'autofocus': True
        }),
        label='Passwort',
        help_text='Geben Sie Ihr aktuelles Passwort zur Bestätigung ein'
    )


class BackupTokenRegenerateForm(forms.Form):
    """Form for regenerating backup tokens"""
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'autocomplete': 'current-password'
        }),
        label='Passwort',
        help_text='Geben Sie Ihr Passwort ein, um neue Backup-Codes zu generieren'
    )


class PersonForm(forms.ModelForm):
    """Form für das Erstellen und Bearbeiten von Personen (Legacy)"""

    class Meta:
        model = Person
        fields = [
            "familienzweig",
            "vorname",
            "nachname",
            "geburtsdatum",
            "email",
            "telefon",
            "iban",
            "adresse",
            "notizen",
            "aktiv",
        ]

        widgets = {
            "familienzweig": forms.Select(attrs={"class": "form-select"}),
            "vorname": forms.TextInput(attrs={"class": "form-control"}),
            "nachname": forms.TextInput(attrs={"class": "form-control"}),
            "geburtsdatum": forms.DateInput(
                attrs={"class": "form-control", "type": "date"}
            ),
            "email": forms.EmailInput(attrs={"class": "form-control"}),
            "telefon": forms.TextInput(attrs={"class": "form-control"}),
            "iban": forms.TextInput(
                attrs={"class": "form-control", "placeholder": "DE89370400440532013000"}
            ),
            "adresse": forms.Textarea(attrs={"class": "form-control", "rows": 3}),
            "notizen": forms.Textarea(attrs={"class": "form-control", "rows": 3}),
            "aktiv": forms.CheckboxInput(attrs={"class": "form-check-input"}),
        }

        labels = {
            "familienzweig": "Familienzweig",
            "vorname": "Vorname *",
            "nachname": "Nachname *",
            "geburtsdatum": "Geburtsdatum",
            "email": "E-Mail",
            "telefon": "Telefon",
            "iban": "IBAN",
            "adresse": "Adresse",
            "notizen": "Notizen",
            "aktiv": "Aktiv",
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Markiere Pflichtfelder
        self.fields["vorname"].required = True
        self.fields["nachname"].required = True
