from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission

from apps.core.authentication.models import Institution
from apps.core.permissions.access import iilmp_role_groups
from apps.core.permissions.roles import UserRole

User = get_user_model()

# Inputs rely on `static/css/input.css` @layer base; only pass attrs that base does not set.
_cb = {"class": "h-4 w-4 rounded border-ruforum-border text-ruforum-primary focus:ring-ruforum-primary"}
_select_multi = {
    "class": "min-h-32 w-full rounded-lg border border-ruforum-border bg-white px-3 py-2 text-sm text-ruforum-text shadow-sm focus:border-ruforum-primary focus:outline-none focus:ring-2 focus:ring-ruforum-primary/[0.18]"
}
_ADDITIONAL_ROLES_HELP = (
    "Custom Groups created in Access control → Roles. Their permissions layer on top of "
    "the Role above, which still drives most permission logic."
)


class UserCreateForm(forms.ModelForm):
    password1 = forms.CharField(
        label="Password",
        strip=False,
        widget=forms.PasswordInput(
            attrs={
                "autocomplete": "new-password",
                "minlength": "8",
            }
        ),
    )
    password2 = forms.CharField(
        label="Confirm password",
        strip=False,
        widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
    )
    send_invitation_email = forms.BooleanField(
        label="Send invitation email",
        required=False,
        initial=True,
        help_text=(
            "Sends a secure link to set a password. The password you enter above is not emailed."
        ),
        widget=forms.CheckboxInput(attrs=_cb),
    )
    additional_roles = forms.ModelMultipleChoiceField(
        queryset=Group.objects.exclude(pk__in=iilmp_role_groups()).order_by("name"),
        required=False,
        widget=forms.SelectMultiple(attrs=_select_multi),
        label="Additional roles",
        help_text=_ADDITIONAL_ROLES_HELP,
    )

    def __init__(self, *args, actor=None, **kwargs):
        self.actor = actor
        super().__init__(*args, **kwargs)
        self.fields["institution"].queryset = Institution.objects.order_by("name")
        self.fields["institution"].required = False
        self.fields["role"].choices = [("", "— Select role —")] + list(UserRole.choices)
        if actor and not actor.is_superuser:
            self.fields.pop("is_staff", None)

    class Meta:
        model = User
        fields = ("email", "first_name", "last_name", "phone", "institution", "role", "is_active", "is_staff")
        widgets = {
            "email": forms.EmailInput(
                attrs={
                    "autocomplete": "email",
                    "inputmode": "email",
                    "spellcheck": "false",
                }
            ),
            "first_name": forms.TextInput(attrs={"autocomplete": "given-name"}),
            "last_name": forms.TextInput(attrs={"autocomplete": "family-name"}),
            "phone": forms.TextInput(
                attrs={
                    "autocomplete": "tel",
                    "inputmode": "tel",
                    "placeholder": "e.g. +256 …",
                }
            ),
            "institution": forms.Select(attrs={"autocomplete": "organization"}),
            "role": forms.Select(attrs={}),
            "is_active": forms.CheckboxInput(attrs=_cb),
            "is_staff": forms.CheckboxInput(attrs=_cb),
        }

    def clean(self):
        data = super().clean()
        p1, p2 = data.get("password1"), data.get("password2")
        if p1 and p2 and p1 != p2:
            self.add_error("password2", "Passwords do not match.")
        return data

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


class UserManageForm(forms.ModelForm):
    user_permissions = forms.ModelMultipleChoiceField(
        queryset=Permission.objects.select_related("content_type").order_by(
            "content_type__app_label", "codename"
        ),
        required=False,
        widget=forms.SelectMultiple(
            attrs={"class": "min-h-32 w-full rounded-lg border border-ruforum-border bg-white px-3 py-2 text-sm text-ruforum-text shadow-sm focus:border-ruforum-primary focus:outline-none focus:ring-2 focus:ring-ruforum-primary/[0.18]"},
        ),
        label="Extra permissions (direct on user)",
        help_text="In addition to permissions inherited from the role group below.",
    )
    additional_roles = forms.ModelMultipleChoiceField(
        queryset=Group.objects.exclude(pk__in=iilmp_role_groups()).order_by("name"),
        required=False,
        widget=forms.SelectMultiple(attrs=_select_multi),
        label="Additional roles",
        help_text=_ADDITIONAL_ROLES_HELP,
    )

    class Meta:
        model = User
        fields = (
            "first_name",
            "last_name",
            "phone",
            "institution",
            "role",
            "is_active",
            "is_staff",
            "user_permissions",
        )
        widgets = {
            "first_name": forms.TextInput(attrs={"autocomplete": "given-name"}),
            "last_name": forms.TextInput(attrs={"autocomplete": "family-name"}),
            "phone": forms.TextInput(attrs={"autocomplete": "tel", "inputmode": "tel"}),
            "institution": forms.Select(attrs={"autocomplete": "organization"}),
            "role": forms.Select(attrs={}),
            "is_active": forms.CheckboxInput(attrs=_cb),
            "is_staff": forms.CheckboxInput(attrs=_cb),
        }

    def __init__(self, *args, actor=None, **kwargs):
        self.actor = actor
        super().__init__(*args, **kwargs)
        self.fields["institution"].queryset = Institution.objects.order_by("name")
        self.fields["institution"].required = False
        self.fields["role"].choices = [("", "— No role —")] + list(UserRole.choices)
        if self.instance.pk:
            self.fields["additional_roles"].initial = self.instance.groups.exclude(
                pk__in=iilmp_role_groups()
            )
        if self.actor and not self.actor.is_superuser:
            self.fields.pop("is_staff", None)

    def clean(self):
        data = super().clean()
        if self.actor and self.instance.pk == self.actor.pk and not data.get("is_active", True):
            raise forms.ValidationError("You cannot deactivate your own account.")
        return data
