from typing import Any

from django import forms
from django.core.exceptions import ValidationError
from django.core import validators
from django.utils.translation import gettext_lazy as _

from module_project import constants

from . import models
# from .backend import EmailBackend
# from phonenumber_field.formfields import PhoneNumberField
from .iam_constant import PRINCIPAL_TYPE_ADMIN, PRINCIPAL_TYPE_SUBADMIN
from django.contrib.auth import authenticate


class CustomAuthenticationForm(forms.Form):
    email = forms.EmailField(
        max_length=254,
        widget=forms.TextInput(attrs={"autofocus": True}),
        label=_("Email"),
    )
    password = forms.CharField(
        label=_("Password"),
        strip=False,
        widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}),
    )

    def clean(self):
        email = self.cleaned_data.get("email")
        password = self.cleaned_data.get("password")
        self.user = None
        if email and password:

            user = authenticate(email=email, password=password)

            if user is None:
                raise ValidationError({"__all__": [constants.INVALID_EMAIL_PASSWORD]})
            elif not user.is_active:
                raise ValidationError({"__all__": [constants.ACCOUNT_DEACTIVATED]})
            self.user = user
        return self.cleaned_data


class IAmPrincipalForm(forms.ModelForm):
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={"autocomplete": "off"}),
        validators=[
            validators.MinLengthValidator(
                limit_value=6, message="Password must be at least 6 characters long. "
            )
        ],
    )
    confirm_password = forms.CharField(
        widget=forms.PasswordInput(attrs={"autocomplete": "off"})
    )

    class Meta:
        model = models.IAmPrincipal
        fields = [
            "principal_type",
            "first_name",
            "last_name",
            "email",
            "password",
            "confirm_password",
        ]

    def __init__(self, *args, **kwargs):
        instance = kwargs.get("instance")
        super().__init__(*args, **kwargs)
        self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter(
            active=True, deleted=False, name__in=(PRINCIPAL_TYPE_ADMIN, PRINCIPAL_TYPE_SUBADMIN)
        )
        # If it's a create action, exclude 'is_active' field
        if instance is not None and instance.pk is not None:
            self.fields.pop("password", None)
            self.fields.pop("confirm_password", None)

    def clean_email(self):
        email = self.cleaned_data.get("email")
        # Skip uniqueness validation if it's an update action (instance exists)
        if self.instance and self.instance.email == email:
            return email
        if models.IAmPrincipal.objects.filter(email=email).exists():
            raise forms.ValidationError(constants.EMAIL_EXISTS)

        return email

    def save(self, commit=True):
        instance = super().save(commit=False)
        # Check if it's a new object (create action) or an existing one (update action)
        if not instance.pk:  # pk is None for new objects
            instance.username = self.cleaned_data["email"]
            instance.set_password(self.cleaned_data["password"])

        principal_type = self.cleaned_data.get("principal_type")
        if principal_type is not None:
            # Set is_superuser and is_staff based on principal_type
            if principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_ADMIN):
                instance.is_superuser = True
            elif principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_SUBADMIN):
                instance.is_superuser = False
                instance.is_staff = True
        if commit:
            instance.save()
        return instance


class IAmPrincipalProfileForm(forms.ModelForm):
    GENDER_CHOICES = (
        ("male", "Male"),
        ("female", "Female"),
        ("other", "Other"),
    )
    first_name = forms.CharField(required=True)
    last_name = forms.CharField(required=True)
    email = forms.EmailField(required=True)
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={"autocomplete": "off"})
    )
    confirm_password = forms.CharField(
        widget=forms.PasswordInput(attrs={"autocomplete": "off"})
    )
    # date_of_birth = forms.CharField(widget=forms.DateInput(attrs={'type': 'date'}))
    phone_number = forms.CharField(
        widget=forms.TextInput(),
    )
    # is_staff = forms.BooleanField(
    #     label="Staff Status",
    #     label_suffix="",
    #     initial=True,
    #     required=False,
    #     help_text="Check this box to designate that this user will be assigned permissions in the future.",
    # )
    # is_superuser = forms.BooleanField(
    #     label="SuperAdmin Status",
    #     label_suffix="",
    #     required=False,
    #     help_text="Check this box to designates that this user has all permissions without explicitly assigning them.",
    # )
    # gender = forms.ChoiceField(choices=GENDER_CHOICES)

    class Meta:
        model = models.IAmPrincipal
        fields = [
            "principal_type",
            "first_name",
            "last_name",
            "email",
            "password",
            "confirm_password",
            # 'gender',
            # 'date_of_birth',
            "phone_number",
            # 'address_line1',
            # 'address_line2',
            # 'city',
            # 'state',
            # 'country',
            # 'post_code',
            # 'profile_photo',
            # "is_staff",
            # "is_superuser",
        ]

    def __init__(self, *args, **kwargs):
        instance = kwargs.get("instance")
        super().__init__(*args, **kwargs)
        self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter(
            active=True, deleted=False
        )
        # self.fields['principal_source'].queryset = models.IAmPrincipalSource.objects.filter(active=True, deleted=False)
        # Check if an instance is provided and customize the form fields accordingly
        if instance is not None:
            # Exclude the 'password' and 'confirm_password' fields
            self.fields.pop("password", None)
            self.fields.pop("confirm_password", None)

            # Make the 'email' field read-only
            self.fields["email"].widget.attrs["readonly"] = True

            # Modify the 'is_superuser' field to be not required
            # self.fields["is_superuser"].required = False
            # self.fields["is_staff"].required = False

            # Add or modify the 'is_active' field
            self.fields["is_active"] = forms.BooleanField(
                label="Active",
                initial=instance.is_active,
                help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
                required=False,
            )

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")

        if password and confirm_password and password != confirm_password:
            self.add_error("confirm_password", "Password does not match")
        return cleaned_data

    def save(self, commit=True):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password"])
        if commit:
            user.save()
        return user

class ProfileEditForm(forms.ModelForm):
    gender = forms.ChoiceField(choices=(('Male', 'Male'),('Female', 'Female'),('Other', 'Other')))
    profile_photo = forms.ImageField(required=False)

    class Meta:
        model = models.IAmPrincipal
        fields = [
            "profile_photo",
            "first_name",
            "last_name",
            "date_of_birth",
            "gender",
            "phone_no"
        ]
        labels = {
            'phone_no': 'Phone Number',  # Map phone_no field to phone_number_label variable
        }


class IAmPrincipalResourceLinkForm(IAmPrincipalForm):

    class Meta:
        model = models.IAmPrincipal
        fields = [
            "principal_type",
            "first_name",
            "last_name",
            "email",
            "password",
            "confirm_password",
            "principal_resource",
        ]

    principal_resource = forms.ModelMultipleChoiceField(
        label="Module Permission",
        queryset=models.IAmAppResource.objects.filter(active=True, deleted=False),
        required=False,
        widget=forms.widgets.SelectMultiple(
            attrs={"class": "form_select js-example-basic-multiple"}
        ),
    )

    def save(self, commit=True):
        # First, save the instance of the IAmPrincipal model as usual
        principal = super().save(commit=False)
        # If the principal_resource field has data
        if self.cleaned_data['principal_resource']:
            # Get the principal_resource data
            principal_resource_data = self.cleaned_data['principal_resource']
            # Update the many-to-many relationship
            principal.principal_resource.set(principal_resource_data)
        # Save the instance to the database
        if commit:
            principal.save()


class IAmPrincipalGroupLinkForm(IAmPrincipalForm):

    class Meta:
        model = models.IAmPrincipal
        fields = [
            "principal_type",
            "first_name",
            "last_name",
            "email",
            "password",
            "confirm_password",
            "principal_group",
        ]

    principal_group = forms.ModelMultipleChoiceField(
        label="Groups",
        queryset=models.IAmPrincipalGroup.objects.filter(active=True, deleted=False),
        required=False,
        widget=forms.widgets.SelectMultiple(
            attrs={"class": "form_select js-example-basic-multiple"}
        ),
    )

    def save(self, commit=True):
        # First, save the instance of the IAmPrincipal model as usual
        principal = super().save(commit=False)
        # If the principal_group field has data
        if self.cleaned_data['principal_group']:
            # Get the principal_group data
            principal_group_data = self.cleaned_data['principal_group']
            # Update the many-to-many relationship
            principal.principal_group.set(principal_group_data)
        # Save the instance to the database
        if commit:
            principal.save()

class IAmPrincipalTypeForm(forms.ModelForm):
    class Meta:
        model = models.IAmPrincipalType
        fields = ["name", "active"]

    def __init__(self, *args, **kwargs):
        instance = kwargs.get("instance")
        super().__init__(*args, **kwargs)

        if instance is None:
            self.fields.pop("active")


class IAmPrincipalGroupRoleLinkForm(forms.ModelForm):
    class Meta:
        model = models.IAmPrincipalGroup
        fields = ["name", "role", "active"]

    role = forms.ModelMultipleChoiceField(
        queryset=models.IAmRole.objects.filter(active=True, deleted=False),
        required=False,
        widget=forms.widgets.SelectMultiple(
            attrs={"class": "form-select js-example-basic-multiple"}
        ),
    )

    def __init__(self, *args, **kwargs):
        instance = kwargs.get("instance")
        # data = kwargs.get('data')
        super().__init__(*args, **kwargs)

        if instance is None:
            # This is an add operation, exclude the 'active' field
            self.fields.pop("active")


class IAmPrincipalRoleAppResourceActionLinkForm(forms.ModelForm):
    class Meta:
        model = models.IAmRole
        fields = ["name", "active", "app_resource_action"]
        required = {"app_resource_action": False}

    app_resource_action = forms.ModelMultipleChoiceField(
        queryset=models.IAmAppResourceActionLink.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False,
    )

    def __init__(self, *args, **kwargs):
        instance = kwargs.get("instance")
        super().__init__(*args, **kwargs)

        if instance is None:
            self.fields.pop("active")
