from django import forms
from django.contrib import admin
from django.forms.utils import flatatt
from django.utils.html import format_html
from django.utils.translation import gettext as _

from .models import MailAddress, MailAddressForward, MailAddressMailbox, Mailbox

PASSWORD_MISMATCH_ERROR = _("Passwords don't match")


class ReadOnlyPasswordHashWidget(forms.Widget):
    def render(self, name, value, attrs, renderer=None):
        final_attrs = self.build_attrs(attrs)
        summary = format_html("<strong>{0}</strong>: {1} ", _("Hash"), value)
        return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)


class ReadOnlyPasswordHashField(forms.Field):
    widget = ReadOnlyPasswordHashWidget

    def __init__(self, *args, **kwargs):
        kwargs.setdefault("required", False)
        super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)

    def bound_data(self, data, initial):
        return initial

    def has_changed(self, initial, data):
        return False


class MailboxCreationForm(forms.ModelForm):
    """
    A form for creating mailboxes.

    """

    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
    password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)

    class Meta:
        model = Mailbox
        fields = ("osuser",)

    def clean_password2(self):
        """
        Check that the two password entries match.

        """
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError(PASSWORD_MISMATCH_ERROR)
        return password2

    def save(self, commit=True):
        """
        Save the provided password in hashed format.

        """
        mailbox = super(MailboxCreationForm, self).save(commit=False)
        mailbox.username = Mailbox.objects.get_next_mailbox_name(mailbox.osuser)
        mailbox.set_password(self.cleaned_data["password1"])
        if commit:
            mailbox.save()
        return mailbox


class MailboxChangeForm(forms.ModelForm):
    """
    A form for updating mailboxes.

    """

    password = ReadOnlyPasswordHashField()

    class Meta:
        model = Mailbox
        fields = ("username", "password", "osuser", "active")

    def clean_password(self):
        return self.initial["password"]


class ActivationChangeMixin(object):
    def activate(self, request, queryset):
        queryset.update(active=True)

    def deactivate(self, request, queryset):
        queryset.update(active=False)

    activate.short_description = _("Activate")
    deactivate.short_description = _("Deactivate")


class MailboxAdmin(ActivationChangeMixin, admin.ModelAdmin):
    """
    Custom admin page for mailboxes.

    """

    form = MailboxChangeForm
    add_form = MailboxCreationForm

    actions = ["activate", "deactivate"]

    list_display = ("username", "osuser", "active")
    list_filter = ("active", "osuser")
    fieldsets = ((None, {"fields": ("osuser", "username", "password", "active")}),)
    add_fieldsets = (
        (None, {"classes": ("wide",), "fields": ("osuser", "password1", "password2")}),
    )
    search_fields = ("username",)
    ordering = ("username",)
    filter_horizontal = ()

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(MailboxAdmin, self).get_fieldsets(request, obj)

    def get_form(self, request, obj=None, **kwargs):
        """
        Use special form during mailbox creation.

        """
        defaults = {}
        if obj is None:
            defaults.update(
                {
                    "form": self.add_form,
                    "fields": admin.options.flatten_fieldsets(self.add_fieldsets),
                }
            )
        defaults.update(kwargs)
        return super(MailboxAdmin, self).get_form(request, obj, **defaults)


class MailAddressMailboxInline(admin.TabularInline):
    model = MailAddressMailbox


class MailAddressForwardInline(admin.TabularInline):
    model = MailAddressForward


class MailAddressAdmin(ActivationChangeMixin, admin.ModelAdmin):
    actions = ["activate", "deactivate"]

    list_display = ("__str__", "mailaddressmailbox", "active")
    list_filter = ("active", "domain")

    inlines = [MailAddressMailboxInline, MailAddressForwardInline]


admin.site.register(Mailbox, MailboxAdmin)
admin.site.register(MailAddress, MailAddressAdmin)
