from django.contrib.auth.decorators import login_required, user_passes_test
from django.forms import ModelForm, CharField, PasswordInput
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render
from django.db import IntegrityError

from multimail import owner
from multimail.models import Domain, Mailbox, Alias
from multimail.owner import user_from_request, may_own_domain


class DomainForm(ModelForm):
    class Meta:
        model = Domain
        fields = '__all__'


class MailboxForm(ModelForm):
    plain_password = CharField(label='Password', required=False, widget=PasswordInput())
    class Meta:
        model = Mailbox
        fields = ['domain', 'username', 'plain_password', 'quota', 'sendonly', 'enabled']

    def save(self, commit=True):
        mailbox = super(MailboxForm, self).save(commit=False)
        if not self.cleaned_data["plain_password"] == '':
            mailbox.set_password(self.cleaned_data["plain_password"])
        if commit:
            mailbox.save()
        return mailbox


class AliasForm(ModelForm):
    class Meta:
        model = Alias
        fields = '__all__'


class PasswdForm(ModelForm):
    plain_password = CharField(label='Password', required=False, widget=PasswordInput())

    class Meta:
        model = Mailbox
        fields = ['plain_password']

    def save(self, commit=True):
        mailbox = super(PasswdForm, self).save(commit=False)
        if not self.cleaned_data["plain_password"] == '':
            mailbox.set_password(self.cleaned_data["plain_password"])
        if commit:
            mailbox.save()
        return mailbox


@user_passes_test(owner.may_own_domain, login_url='/login/')
def edit_domain(request, domain_id):
    try:
        user = user_from_request(request)
        domain = Domain.objects.filter(admin__admin=user['name'], admin__source=user['source']).get(pk=domain_id)
    except:
        raise Http404
    if request.method == 'POST':
        form = DomainForm(request.POST, instance=domain)
        try:
            if form.is_valid():
                form.save()
                return HttpResponseRedirect('/domains/')

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = DomainForm(instance=domain)

    return render(request, 'multimail/edit.html', {'form': form})


@user_passes_test(owner.may_own_domain, login_url='/login/')
def new_domain(request):
    user = user_from_request(request)
    if request.method == 'POST':
        form = DomainForm(request.POST)
        try:
            if form.is_valid():
                domain = form.save()
                domain.admin.create(admin=user['name'], source=user['source'])
                return HttpResponseRedirect('/domains/')

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = DomainForm()

    return render(request, 'multimail/edit.html', {'form': form})


@user_passes_test(owner.may_own_domain, login_url='/login/')
def edit_mailbox(request, mailbox_id):
    try:
        user = user_from_request(request)
        domains = [o.domain for o in Domain.objects.filter(admin__admin=user['name'], admin__source=user['source'])]
        mailbox = Mailbox.objects.filter(domain__in=domains).get(pk=mailbox_id)
    except:
        raise Http404
    if request.method == 'POST':
        form = MailboxForm(request.POST, instance=mailbox)
        try:
            if form.is_valid() and form.cleaned_data['domain'] in domains:
                form.save()
                return HttpResponseRedirect('/mailboxes/')
            else:
                if not form.cleaned_data['domain'] in domains:
                    form.errors.clear()
                    form.add_error(None, "You don't own this domain")

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = MailboxForm(instance=mailbox)

    return render(request, 'multimail/edit.html', {'form': form})


@user_passes_test(owner.may_own_domain, login_url='/login/')
def new_mailbox(request):
    if request.method == 'POST':
        user = user_from_request(request)
        domains = [o.domain for o in Domain.objects.filter(admin__admin=user['name'], admin__source=user['source'])]
        form = MailboxForm(request.POST)
        try:
            if form.is_valid() and form.cleaned_data['domain'] in domains:
                form.save()
                return HttpResponseRedirect('/mailboxes/')
            else:
                if not form.cleaned_data['domain'] in domains:
                    form.errors.clear()
                    form.add_error(None, "You don't own this domain")

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = MailboxForm()

    return render(request, 'multimail/edit.html', {'form': form})


@user_passes_test(owner.may_own_domain, login_url='/login/')
def edit_alias(request, alias_id):
    try:
        user = user_from_request(request)
        domains = [o.domain for o in Domain.objects.filter(admin__admin=user['name'], admin__source=user['source'])]
        alias = Alias.objects.filter(source_domain__in=domains).get(pk=alias_id)
    except:
        raise Http404
    if request.method == 'POST':
        form = AliasForm(request.POST, instance=alias)
        try:
            if form.is_valid() and form.cleaned_data['source_domain'] in domains:
                form.save()
                return HttpResponseRedirect('/aliases/')
            else:
                if not form.cleaned_data['source_domain'] in domains:
                    form.errors.clear()
                    form.add_error(None, "You don't own this domain")

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = AliasForm(instance=alias)

    return render(request, 'multimail/edit.html', {'form': form})


@user_passes_test(owner.may_own_domain, login_url='/login/')
def new_alias(request):
    if request.method == 'POST':
        user = user_from_request(request)
        domains = [o.domain for o in Domain.objects.filter(admin__admin=user['name'], admin__source=user['source'])]
        form = AliasForm(request.POST)
        try:
            if form.is_valid() and form.cleaned_data['source_domain'] in domains:
                form.save()
                return HttpResponseRedirect('/aliases/')
            else:
                if not form.cleaned_data['source_domain'] in domains:
                    form.errors.clear()
                    form.add_error(None, "You don't own this domain")

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = AliasForm()

    return render(request, 'multimail/edit.html', {'form': form})


@login_required(login_url='/login/')
def mailbox_passwd(request):
    if may_own_domain(request.user):
        raise Http404
    mailbox = request.user.mailbox
    if request.method == 'POST':
        form = PasswdForm(request.POST, instance=mailbox)
        try:
            if form.is_valid():
                form.save()
                return HttpResponseRedirect('')

        except IntegrityError as e:
            form.add_error(None, e)

    else:
        form = PasswdForm(instance=mailbox)

    return render(request, 'multimail/mailboxindex.html', {'form': form})
