"""Administration form for e-mail settings."""

import logging

from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.sites.models import Site
from django.utils.translation import gettext, gettext_lazy as _
from djblets.siteconfig.forms import SiteSettingsForm
from djblets.siteconfig.models import SiteConfiguration

from reviewboard.admin.siteconfig import load_site_config
from reviewboard.notifications.email.message import EmailMessage


logger = logging.getLogger(__name__)


class EMailSettingsForm(SiteSettingsForm):
    """E-mail settings for Review Board."""

    FROM_SPOOFING_CHOICES = (
        (EmailMessage.FROM_SPOOFING_SMART,
         _('Auto (when allowed by DMARC record)')),
        (EmailMessage.FROM_SPOOFING_ALWAYS, _('Always')),
        (EmailMessage.FROM_SPOOFING_NEVER, _('Never')),
    )

    mail_send_review_mail = forms.BooleanField(
        label=_('Send e-mails for review requests and reviews'),
        required=False)
    mail_send_review_close_mail = forms.BooleanField(
        label=_('Send e-mails when review requests are closed'),
        required=False)
    mail_send_new_user_mail = forms.BooleanField(
        label=_('Send e-mails to administrators when new users register '
                'accounts'),
        required=False)
    mail_send_password_changed_mail = forms.BooleanField(
        label=_('Send e-mails to users when they change their password'),
        required=False)
    mail_enable_autogenerated_header = forms.BooleanField(
        label=_('Enable "Auto-Submitted: auto-generated" header'),
        help_text=_('Marks outgoing e-mails as "auto-generated" to avoid '
                    'auto-replies. Disable this if your mailing list rejects '
                    '"auto-generated" e-mails.'),
        required=False)
    mail_default_from = forms.CharField(
        label=_('Default From address'),
        help_text=_('The e-mail address that all e-mails will be sent from. '
                    'The "Sender" header will be used to make e-mails appear '
                    'to come from the user triggering the e-mail.'),
        required=False,
        widget=forms.TextInput(attrs={'size': '50'}))
    mail_from_spoofing = forms.ChoiceField(
        label=_("Use the user's From address"),
        choices=FROM_SPOOFING_CHOICES,
        required=False,
        help_text=_('Depending on the sender domain\'s DKIM/SPF '
                    'configuration, e-mails may be marked as suspicious when '
                    'sending from the user\'s own e-mail address. '
                    '<strong>Auto</strong> will check the domain\'s DMARC '
                    'record before using their address, falling back to the '
                    '"Default From address" above. <strong>Always</strong> '
                    'will use it unconditionally. <strong>Never</strong> will '
                    'use the default address for every e-mail.'))
    mail_host = forms.CharField(
        label=_('Mail server'),
        required=False,
        widget=forms.TextInput(attrs={'size': '50'}))
    mail_port = forms.IntegerField(
        label=_('Port'),
        required=False,
        widget=forms.TextInput(attrs={'size': '5'}))
    mail_host_user = forms.CharField(
        label=_('Username'),
        required=False,
        widget=forms.TextInput(attrs={'size': '30', 'autocomplete': 'off'}))
    mail_host_password = forms.CharField(
        widget=forms.PasswordInput(attrs={'size': '30', 'autocomplete': 'off'},
                                   render_value=True),
        label=_('Password'),
        required=False)
    mail_use_tls = forms.BooleanField(
        label=_('Use TLS for authentication'),
        required=False)

    send_test_mail = forms.BooleanField(
        label=_('Send a test e-mail after saving'),
        help_text=_('Send an e-mail to yourself using these server settings.'),
        required=False)

    def clean_mail_host(self):
        """Clean the mail_host field.

        This will strip all whitespace around the value.

        Returns:
            unicode:
            The ``mail_host`` field, with all whitespace stripped.
        """
        return self.cleaned_data['mail_host'].strip()

    def save(self):
        """Save the form.

        This will write the new configuration to the database. It will then
        force a site configuration reload.
        """
        super(EMailSettingsForm, self).save()

        # Reload any important changes into the Django settings.
        load_site_config()

        if self.cleaned_data['send_test_mail']:
            site = Site.objects.get_current()
            siteconfig = SiteConfiguration.objects.get_current()
            product_name = settings.PRODUCT_NAME
            request = self.request

            site_url = '%s://%s' % (siteconfig.get('site_domain_method'),
                                    site.domain)

            if request and request.user.is_authenticated:
                to_user = request.user.email
            else:
                to_user = siteconfig.get('site_admin_email')

            try:
                message = EmailMessage(
                    subject=(
                        gettext('%s e-mail settings test')
                        % product_name
                    ),
                    text_body=(
                        gettext("This is a test of the e-mail settings "
                                "for the %(product)s server at %(url)s. "
                                "If you got this, you're all set!")
                        % {
                            'product': product_name,
                            'url': site_url,
                        }
                    ),
                    from_email=siteconfig.get('mail_default_from'),
                    to=[to_user])

                message.send()
            except Exception as e:
                error = str(e)

                if request is not None:
                    messages.error(
                        request,
                        gettext('Failed to send the test e-mail: "%s". Check '
                                'the server logs for additional details.')
                        % error)

                logger.exception('Failed to send test e-mail to %s: %s',
                                 to_user, error)

    class Meta:
        title = _('E-Mail Settings')
        save_blacklist = ('send_test_mail',)

        fieldsets = (
            {
                'title': _('E-Mail Notification Settings'),
                'classes': ('wide',),
                'fields': ('mail_send_review_mail',
                           'mail_send_review_close_mail',
                           'mail_send_new_user_mail',
                           'mail_send_password_changed_mail'),
            },
            {
                'title': _('E-Mail Delivery Settings'),
                'classes': ('wide',),
                'fields': ('mail_default_from',
                           'mail_from_spoofing',
                           'mail_enable_autogenerated_header'),
            },
            {
                'title': _('E-Mail Server Settings'),
                'classes': ('wide',),
                'fields': ('mail_host', 'mail_port', 'mail_host_user',
                           'mail_host_password', 'mail_use_tls',
                           'send_test_mail'),
            },
        )
